lody 0.67.3 → 0.68.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
CHANGED
|
@@ -4188,7 +4188,7 @@ let __tla = Promise.all([
|
|
|
4188
4188
|
}
|
|
4189
4189
|
}
|
|
4190
4190
|
const name$1 = "lody";
|
|
4191
|
-
const version$3 = "0.
|
|
4191
|
+
const version$3 = "0.68.0";
|
|
4192
4192
|
const description$1 = "Lody Agent CLI tool for managing remote command execution";
|
|
4193
4193
|
const type$2 = "module";
|
|
4194
4194
|
const main$4 = "dist/index.js";
|
|
@@ -4534,6 +4534,274 @@ let __tla = Promise.all([
|
|
|
4534
4534
|
return void 0;
|
|
4535
4535
|
};
|
|
4536
4536
|
const isBuiltinAgentType = (agentType) => agentType === "claude" || agentType === "codex";
|
|
4537
|
+
const CODEX_STATIC_MODES = [
|
|
4538
|
+
{
|
|
4539
|
+
id: "read-only",
|
|
4540
|
+
name: "Read-only",
|
|
4541
|
+
description: "Requires approval to edit files and run commands."
|
|
4542
|
+
},
|
|
4543
|
+
{
|
|
4544
|
+
id: "agent",
|
|
4545
|
+
name: "Agent",
|
|
4546
|
+
description: "Read and edit files, and run commands."
|
|
4547
|
+
},
|
|
4548
|
+
{
|
|
4549
|
+
id: "agent-full-access",
|
|
4550
|
+
name: "Agent (full access)",
|
|
4551
|
+
description: "Codex can edit files outside this workspace and run commands with network access. Exercise caution when using."
|
|
4552
|
+
}
|
|
4553
|
+
];
|
|
4554
|
+
const CODEX_STATIC_MODELS = [
|
|
4555
|
+
{
|
|
4556
|
+
modelId: "gpt-5.5",
|
|
4557
|
+
name: "gpt-5.5",
|
|
4558
|
+
description: "Latest frontier Codex model"
|
|
4559
|
+
},
|
|
4560
|
+
{
|
|
4561
|
+
modelId: "gpt-5.4",
|
|
4562
|
+
name: "gpt-5.4",
|
|
4563
|
+
description: "Frontier Codex model"
|
|
4564
|
+
},
|
|
4565
|
+
{
|
|
4566
|
+
modelId: "gpt-5.4-mini",
|
|
4567
|
+
name: "gpt-5.4-mini",
|
|
4568
|
+
description: "Smaller, faster Codex model"
|
|
4569
|
+
}
|
|
4570
|
+
];
|
|
4571
|
+
const CODEX_REASONING_OPTIONS = [
|
|
4572
|
+
{
|
|
4573
|
+
value: "low",
|
|
4574
|
+
name: "low",
|
|
4575
|
+
description: "Fastest responses"
|
|
4576
|
+
},
|
|
4577
|
+
{
|
|
4578
|
+
value: "medium",
|
|
4579
|
+
name: "medium",
|
|
4580
|
+
description: "Balanced reasoning"
|
|
4581
|
+
},
|
|
4582
|
+
{
|
|
4583
|
+
value: "high",
|
|
4584
|
+
name: "high",
|
|
4585
|
+
description: "More reasoning for difficult tasks"
|
|
4586
|
+
},
|
|
4587
|
+
{
|
|
4588
|
+
value: "xhigh",
|
|
4589
|
+
name: "xhigh",
|
|
4590
|
+
description: "Extra reasoning for complex tasks"
|
|
4591
|
+
}
|
|
4592
|
+
];
|
|
4593
|
+
const CODEX_STATIC_CONFIG_OPTIONS = [
|
|
4594
|
+
{
|
|
4595
|
+
id: "mode",
|
|
4596
|
+
name: "Mode",
|
|
4597
|
+
description: "Approval and sandboxing preset for the session",
|
|
4598
|
+
category: "mode",
|
|
4599
|
+
type: "select",
|
|
4600
|
+
currentValue: "agent",
|
|
4601
|
+
options: CODEX_STATIC_MODES.map((mode2) => ({
|
|
4602
|
+
value: mode2.id,
|
|
4603
|
+
name: mode2.name,
|
|
4604
|
+
description: mode2.description ?? void 0
|
|
4605
|
+
}))
|
|
4606
|
+
},
|
|
4607
|
+
{
|
|
4608
|
+
id: "model",
|
|
4609
|
+
name: "Model",
|
|
4610
|
+
description: "Model Codex uses for the session",
|
|
4611
|
+
category: "model",
|
|
4612
|
+
type: "select",
|
|
4613
|
+
currentValue: "gpt-5.5",
|
|
4614
|
+
options: CODEX_STATIC_MODELS.map((model) => ({
|
|
4615
|
+
value: model.modelId,
|
|
4616
|
+
name: model.name,
|
|
4617
|
+
description: model.description ?? void 0
|
|
4618
|
+
}))
|
|
4619
|
+
},
|
|
4620
|
+
{
|
|
4621
|
+
id: "reasoning_effort",
|
|
4622
|
+
name: "Reasoning effort",
|
|
4623
|
+
description: "How much reasoning effort the model should use",
|
|
4624
|
+
category: "thought_level",
|
|
4625
|
+
type: "select",
|
|
4626
|
+
currentValue: "medium",
|
|
4627
|
+
options: CODEX_REASONING_OPTIONS
|
|
4628
|
+
},
|
|
4629
|
+
{
|
|
4630
|
+
id: "fast-mode",
|
|
4631
|
+
name: "Fast mode",
|
|
4632
|
+
description: "1.5x speed, increased usage",
|
|
4633
|
+
category: "fast-mode",
|
|
4634
|
+
type: "select",
|
|
4635
|
+
currentValue: "off",
|
|
4636
|
+
options: [
|
|
4637
|
+
{
|
|
4638
|
+
value: "off",
|
|
4639
|
+
name: "Off",
|
|
4640
|
+
description: "Default speed, normal usage"
|
|
4641
|
+
},
|
|
4642
|
+
{
|
|
4643
|
+
value: "on",
|
|
4644
|
+
name: "On",
|
|
4645
|
+
description: "1.5x speed, increased usage"
|
|
4646
|
+
}
|
|
4647
|
+
]
|
|
4648
|
+
},
|
|
4649
|
+
{
|
|
4650
|
+
id: "plan-mode",
|
|
4651
|
+
name: "Plan mode",
|
|
4652
|
+
description: "Plan without modifying files; switch off to implement the approved plan",
|
|
4653
|
+
category: "plan-mode",
|
|
4654
|
+
type: "select",
|
|
4655
|
+
currentValue: "off",
|
|
4656
|
+
options: [
|
|
4657
|
+
{
|
|
4658
|
+
value: "off",
|
|
4659
|
+
name: "Off",
|
|
4660
|
+
description: "Implement changes normally"
|
|
4661
|
+
},
|
|
4662
|
+
{
|
|
4663
|
+
value: "on",
|
|
4664
|
+
name: "On",
|
|
4665
|
+
description: "Plan without modifying files; switch off to implement the approved plan"
|
|
4666
|
+
}
|
|
4667
|
+
]
|
|
4668
|
+
}
|
|
4669
|
+
];
|
|
4670
|
+
const CLAUDE_STATIC_MODES = [
|
|
4671
|
+
{
|
|
4672
|
+
id: "auto",
|
|
4673
|
+
name: "Auto",
|
|
4674
|
+
description: "Use a model classifier to approve/deny permission prompts"
|
|
4675
|
+
},
|
|
4676
|
+
{
|
|
4677
|
+
id: "default",
|
|
4678
|
+
name: "Default",
|
|
4679
|
+
description: "Standard behavior, prompts for dangerous operations"
|
|
4680
|
+
},
|
|
4681
|
+
{
|
|
4682
|
+
id: "acceptEdits",
|
|
4683
|
+
name: "Accept Edits",
|
|
4684
|
+
description: "Auto-accept file edit operations"
|
|
4685
|
+
},
|
|
4686
|
+
{
|
|
4687
|
+
id: "plan",
|
|
4688
|
+
name: "Plan Mode",
|
|
4689
|
+
description: "Planning mode, no actual tool execution"
|
|
4690
|
+
},
|
|
4691
|
+
{
|
|
4692
|
+
id: "dontAsk",
|
|
4693
|
+
name: "Don't Ask",
|
|
4694
|
+
description: "Don't prompt for permissions, deny if not pre-approved"
|
|
4695
|
+
}
|
|
4696
|
+
];
|
|
4697
|
+
const CLAUDE_STATIC_MODELS = [
|
|
4698
|
+
{
|
|
4699
|
+
modelId: "default",
|
|
4700
|
+
name: "Default",
|
|
4701
|
+
description: "Claude Code default model"
|
|
4702
|
+
},
|
|
4703
|
+
{
|
|
4704
|
+
modelId: "opus",
|
|
4705
|
+
name: "Opus",
|
|
4706
|
+
description: "Claude Opus"
|
|
4707
|
+
},
|
|
4708
|
+
{
|
|
4709
|
+
modelId: "sonnet",
|
|
4710
|
+
name: "Sonnet",
|
|
4711
|
+
description: "Claude Sonnet"
|
|
4712
|
+
},
|
|
4713
|
+
{
|
|
4714
|
+
modelId: "haiku",
|
|
4715
|
+
name: "Haiku",
|
|
4716
|
+
description: "Claude Haiku"
|
|
4717
|
+
}
|
|
4718
|
+
];
|
|
4719
|
+
const CLAUDE_STATIC_CONFIG_OPTIONS = [
|
|
4720
|
+
{
|
|
4721
|
+
id: "mode",
|
|
4722
|
+
name: "Mode",
|
|
4723
|
+
description: "Session permission mode",
|
|
4724
|
+
category: "mode",
|
|
4725
|
+
type: "select",
|
|
4726
|
+
currentValue: "default",
|
|
4727
|
+
options: CLAUDE_STATIC_MODES.map((mode2) => ({
|
|
4728
|
+
value: mode2.id,
|
|
4729
|
+
name: mode2.name,
|
|
4730
|
+
description: mode2.description ?? void 0
|
|
4731
|
+
}))
|
|
4732
|
+
},
|
|
4733
|
+
{
|
|
4734
|
+
id: "model",
|
|
4735
|
+
name: "Model",
|
|
4736
|
+
description: "AI model to use",
|
|
4737
|
+
category: "model",
|
|
4738
|
+
type: "select",
|
|
4739
|
+
currentValue: "default",
|
|
4740
|
+
options: CLAUDE_STATIC_MODELS.map((model) => ({
|
|
4741
|
+
value: model.modelId,
|
|
4742
|
+
name: model.name,
|
|
4743
|
+
description: model.description ?? void 0
|
|
4744
|
+
}))
|
|
4745
|
+
},
|
|
4746
|
+
{
|
|
4747
|
+
id: "effort",
|
|
4748
|
+
name: "Effort",
|
|
4749
|
+
description: "Available effort levels for this model",
|
|
4750
|
+
category: "thought_level",
|
|
4751
|
+
type: "select",
|
|
4752
|
+
currentValue: "default",
|
|
4753
|
+
options: [
|
|
4754
|
+
{
|
|
4755
|
+
value: "default",
|
|
4756
|
+
name: "Default"
|
|
4757
|
+
},
|
|
4758
|
+
{
|
|
4759
|
+
value: "low",
|
|
4760
|
+
name: "Low"
|
|
4761
|
+
},
|
|
4762
|
+
{
|
|
4763
|
+
value: "medium",
|
|
4764
|
+
name: "Medium"
|
|
4765
|
+
},
|
|
4766
|
+
{
|
|
4767
|
+
value: "high",
|
|
4768
|
+
name: "High"
|
|
4769
|
+
}
|
|
4770
|
+
]
|
|
4771
|
+
}
|
|
4772
|
+
];
|
|
4773
|
+
const cloneConfigOption = (option2) => ({
|
|
4774
|
+
...option2,
|
|
4775
|
+
options: option2.options.map((value) => ({
|
|
4776
|
+
...value
|
|
4777
|
+
}))
|
|
4778
|
+
});
|
|
4779
|
+
const cloneStaticCapabilities = (capabilities) => ({
|
|
4780
|
+
modes: capabilities.modes.map((mode2) => ({
|
|
4781
|
+
...mode2
|
|
4782
|
+
})),
|
|
4783
|
+
models: capabilities.models.map((model) => ({
|
|
4784
|
+
...model
|
|
4785
|
+
})),
|
|
4786
|
+
configOptions: capabilities.configOptions.map(cloneConfigOption)
|
|
4787
|
+
});
|
|
4788
|
+
const getStaticBuiltinAcpCapabilities = (cliType, agentType, runtimeOverrides) => {
|
|
4789
|
+
if (cliType !== "builtin" || !agentType || !isBuiltinAgentType(agentType)) {
|
|
4790
|
+
return void 0;
|
|
4791
|
+
}
|
|
4792
|
+
if (hasBuiltinRuntimeOverrideValues(runtimeOverrides)) {
|
|
4793
|
+
return void 0;
|
|
4794
|
+
}
|
|
4795
|
+
return cloneStaticCapabilities(agentType === "claude" ? {
|
|
4796
|
+
modes: CLAUDE_STATIC_MODES,
|
|
4797
|
+
models: CLAUDE_STATIC_MODELS,
|
|
4798
|
+
configOptions: CLAUDE_STATIC_CONFIG_OPTIONS
|
|
4799
|
+
} : {
|
|
4800
|
+
modes: CODEX_STATIC_MODES,
|
|
4801
|
+
models: CODEX_STATIC_MODELS,
|
|
4802
|
+
configOptions: CODEX_STATIC_CONFIG_OPTIONS
|
|
4803
|
+
});
|
|
4804
|
+
};
|
|
4537
4805
|
const leastPermissionModeRank = (value, name2) => {
|
|
4538
4806
|
const normalized = `${value} ${name2}`.toLowerCase().replace(/[\s_-]+/g, "-");
|
|
4539
4807
|
if (normalized.includes("read-only") || normalized.includes("readonly")) return 0;
|
|
@@ -78955,6 +79223,252 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
78955
79223
|
}
|
|
78956
79224
|
}
|
|
78957
79225
|
}
|
|
79226
|
+
const isRecoverableMachineFlockRoomStatus = (status) => status === "disconnected" || status === "error";
|
|
79227
|
+
class MachineFlockSyncCoordinator {
|
|
79228
|
+
repo;
|
|
79229
|
+
workspaceId;
|
|
79230
|
+
logger;
|
|
79231
|
+
random;
|
|
79232
|
+
retryBaseDelayMs;
|
|
79233
|
+
retryMaxDelayMs;
|
|
79234
|
+
states = /* @__PURE__ */ new Map();
|
|
79235
|
+
cleanedUp = false;
|
|
79236
|
+
constructor(options) {
|
|
79237
|
+
this.repo = options.repo;
|
|
79238
|
+
this.workspaceId = options.workspaceId;
|
|
79239
|
+
this.logger = options.logger;
|
|
79240
|
+
this.random = options.random ?? Math.random;
|
|
79241
|
+
this.retryBaseDelayMs = options.retryBaseDelayMs;
|
|
79242
|
+
this.retryMaxDelayMs = options.retryMaxDelayMs;
|
|
79243
|
+
}
|
|
79244
|
+
ensureJoined(machineId, options = {}) {
|
|
79245
|
+
const state2 = this.getState(machineId);
|
|
79246
|
+
return this.ensureStateJoined(state2, options.reason ?? "ensure-joined");
|
|
79247
|
+
}
|
|
79248
|
+
markDirty(machineId, options = {}) {
|
|
79249
|
+
if (this.cleanedUp) {
|
|
79250
|
+
return;
|
|
79251
|
+
}
|
|
79252
|
+
const state2 = this.getState(machineId);
|
|
79253
|
+
state2.dirty = true;
|
|
79254
|
+
state2.dirtyVersion += 1;
|
|
79255
|
+
if (options.resetBackoff) {
|
|
79256
|
+
state2.retryAttempt = 0;
|
|
79257
|
+
}
|
|
79258
|
+
const reason = options.reason ?? "dirty";
|
|
79259
|
+
void this.ensureStateJoined(state2, `dirty:${reason}`).catch((error2) => {
|
|
79260
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock room join failed before background sync (machine=${machineId} reason=${reason}): ${formatErrorMessage(error2)}`);
|
|
79261
|
+
});
|
|
79262
|
+
void this.syncNow(machineId, {
|
|
79263
|
+
...options,
|
|
79264
|
+
reason,
|
|
79265
|
+
scheduleRetry: options.scheduleRetry ?? true
|
|
79266
|
+
});
|
|
79267
|
+
}
|
|
79268
|
+
async syncNow(machineId, options = {}) {
|
|
79269
|
+
if (this.cleanedUp) {
|
|
79270
|
+
return false;
|
|
79271
|
+
}
|
|
79272
|
+
const state2 = this.getState(machineId);
|
|
79273
|
+
if (state2.activeSync) {
|
|
79274
|
+
return await state2.activeSync;
|
|
79275
|
+
}
|
|
79276
|
+
state2.activeSync = this.syncStateNow(state2, options).finally(() => {
|
|
79277
|
+
state2.activeSync = null;
|
|
79278
|
+
});
|
|
79279
|
+
return await state2.activeSync;
|
|
79280
|
+
}
|
|
79281
|
+
retryDirtyNow(reason) {
|
|
79282
|
+
if (this.cleanedUp) {
|
|
79283
|
+
return;
|
|
79284
|
+
}
|
|
79285
|
+
for (const state2 of this.states.values()) {
|
|
79286
|
+
if (!state2.dirty) {
|
|
79287
|
+
continue;
|
|
79288
|
+
}
|
|
79289
|
+
this.clearRetryTimer(state2);
|
|
79290
|
+
state2.retryAttempt = 0;
|
|
79291
|
+
void this.syncNow(state2.machineId, {
|
|
79292
|
+
reason,
|
|
79293
|
+
scheduleRetry: true,
|
|
79294
|
+
resetBackoff: true
|
|
79295
|
+
});
|
|
79296
|
+
}
|
|
79297
|
+
}
|
|
79298
|
+
async cleanUp() {
|
|
79299
|
+
this.cleanedUp = true;
|
|
79300
|
+
const pendingOperations = [];
|
|
79301
|
+
for (const state2 of this.states.values()) {
|
|
79302
|
+
this.clearRetryTimer(state2);
|
|
79303
|
+
if (state2.activeSync) {
|
|
79304
|
+
pendingOperations.push(state2.activeSync);
|
|
79305
|
+
}
|
|
79306
|
+
if (state2.joinPromise) {
|
|
79307
|
+
pendingOperations.push(state2.joinPromise);
|
|
79308
|
+
}
|
|
79309
|
+
this.releaseRoomSubscription(state2);
|
|
79310
|
+
}
|
|
79311
|
+
await Promise.allSettled(pendingOperations);
|
|
79312
|
+
this.states.clear();
|
|
79313
|
+
}
|
|
79314
|
+
async syncStateNow(state2, options) {
|
|
79315
|
+
const reason = options.reason ?? "sync-now";
|
|
79316
|
+
if (options.resetBackoff) {
|
|
79317
|
+
state2.retryAttempt = 0;
|
|
79318
|
+
}
|
|
79319
|
+
this.clearRetryTimer(state2);
|
|
79320
|
+
try {
|
|
79321
|
+
await this.ensureStateJoined(state2, `sync:${reason}`);
|
|
79322
|
+
} catch (error2) {
|
|
79323
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock room join failed before sync (machine=${state2.machineId} reason=${reason}): ${formatErrorMessage(error2)}`);
|
|
79324
|
+
}
|
|
79325
|
+
const syncVersion = state2.dirtyVersion;
|
|
79326
|
+
const timeoutMs = options.timeoutMs ?? readTimeoutEnv("LODY_LORO_SYNC_MACHINE_FLOCK_TIMEOUT_MS", 8e3);
|
|
79327
|
+
const timeoutMessage = `Timeout waiting for machine Flock doc sync (doc=${state2.docId})`;
|
|
79328
|
+
try {
|
|
79329
|
+
const handle = await this.repo.openFlockDoc(state2.docId);
|
|
79330
|
+
await withTimeout$3(handle.syncOnce(), timeoutMs, timeoutMessage);
|
|
79331
|
+
if (state2.dirtyVersion === syncVersion) {
|
|
79332
|
+
state2.dirty = false;
|
|
79333
|
+
state2.retryAttempt = 0;
|
|
79334
|
+
} else if (state2.dirty) {
|
|
79335
|
+
this.scheduleRetry(state2, `${reason}:new-writes`, true);
|
|
79336
|
+
}
|
|
79337
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock doc synced (machine=${state2.machineId} reason=${reason})`);
|
|
79338
|
+
return true;
|
|
79339
|
+
} catch (error2) {
|
|
79340
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock doc sync was not confirmed before continuing (machine=${state2.machineId} reason=${reason}): ${formatErrorMessage(error2)}`);
|
|
79341
|
+
if (options.scheduleRetry ?? true) {
|
|
79342
|
+
state2.dirty = true;
|
|
79343
|
+
this.scheduleRetry(state2, reason, false);
|
|
79344
|
+
}
|
|
79345
|
+
return false;
|
|
79346
|
+
}
|
|
79347
|
+
}
|
|
79348
|
+
async ensureStateJoined(state2, reason) {
|
|
79349
|
+
if (this.cleanedUp) {
|
|
79350
|
+
return;
|
|
79351
|
+
}
|
|
79352
|
+
if (state2.roomSub) {
|
|
79353
|
+
if (!isRecoverableMachineFlockRoomStatus(state2.roomSub.status)) {
|
|
79354
|
+
return;
|
|
79355
|
+
}
|
|
79356
|
+
this.releaseRoomSubscription(state2, state2.roomSub);
|
|
79357
|
+
}
|
|
79358
|
+
if (state2.joinPromise) {
|
|
79359
|
+
return await state2.joinPromise;
|
|
79360
|
+
}
|
|
79361
|
+
state2.joinPromise = (async () => {
|
|
79362
|
+
const handle = await this.repo.openFlockDoc(state2.docId);
|
|
79363
|
+
const sub = await handle.joinRoom();
|
|
79364
|
+
if (this.cleanedUp) {
|
|
79365
|
+
sub.unsubscribe();
|
|
79366
|
+
return;
|
|
79367
|
+
}
|
|
79368
|
+
state2.roomSub = sub;
|
|
79369
|
+
state2.detachRoomStatusListener = sub.onStatusChange((status) => {
|
|
79370
|
+
this.handleRoomStatusChange(state2, sub, status);
|
|
79371
|
+
});
|
|
79372
|
+
this.handleRoomStatusChange(state2, sub, sub.status);
|
|
79373
|
+
if (state2.roomSub !== sub) {
|
|
79374
|
+
return;
|
|
79375
|
+
}
|
|
79376
|
+
void sub.firstSyncedWithRemote.then(() => {
|
|
79377
|
+
if (this.cleanedUp || state2.roomSub !== sub) {
|
|
79378
|
+
return;
|
|
79379
|
+
}
|
|
79380
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock room first sync completed (machine=${state2.machineId} reason=${reason})`);
|
|
79381
|
+
}, (error2) => {
|
|
79382
|
+
if (this.cleanedUp || state2.roomSub !== sub) {
|
|
79383
|
+
return;
|
|
79384
|
+
}
|
|
79385
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock room first sync failed (machine=${state2.machineId} reason=${reason}): ${formatErrorMessage(error2)}`);
|
|
79386
|
+
});
|
|
79387
|
+
})();
|
|
79388
|
+
try {
|
|
79389
|
+
await state2.joinPromise;
|
|
79390
|
+
} finally {
|
|
79391
|
+
state2.joinPromise = null;
|
|
79392
|
+
}
|
|
79393
|
+
}
|
|
79394
|
+
handleRoomStatusChange(state2, sub, status) {
|
|
79395
|
+
if (this.cleanedUp || state2.roomSub !== sub) {
|
|
79396
|
+
return;
|
|
79397
|
+
}
|
|
79398
|
+
if (!isRecoverableMachineFlockRoomStatus(status)) {
|
|
79399
|
+
return;
|
|
79400
|
+
}
|
|
79401
|
+
this.logger.debug(`[${this.workspaceId}] Machine Flock room became ${status}; will rejoin before the next sync (machine=${state2.machineId})`);
|
|
79402
|
+
this.releaseRoomSubscription(state2, sub);
|
|
79403
|
+
if (state2.dirty) {
|
|
79404
|
+
this.scheduleRetry(state2, `room-${status}`, false);
|
|
79405
|
+
}
|
|
79406
|
+
}
|
|
79407
|
+
releaseRoomSubscription(state2, sub = state2.roomSub) {
|
|
79408
|
+
if (!sub || state2.roomSub !== sub) {
|
|
79409
|
+
return;
|
|
79410
|
+
}
|
|
79411
|
+
state2.detachRoomStatusListener?.();
|
|
79412
|
+
state2.detachRoomStatusListener = null;
|
|
79413
|
+
state2.roomSub = null;
|
|
79414
|
+
sub.unsubscribe();
|
|
79415
|
+
}
|
|
79416
|
+
scheduleRetry(state2, reason, resetBackoff) {
|
|
79417
|
+
if (this.cleanedUp || !state2.dirty) {
|
|
79418
|
+
return;
|
|
79419
|
+
}
|
|
79420
|
+
if (resetBackoff) {
|
|
79421
|
+
state2.retryAttempt = 0;
|
|
79422
|
+
}
|
|
79423
|
+
if (state2.retryTimer) {
|
|
79424
|
+
return;
|
|
79425
|
+
}
|
|
79426
|
+
const delayMs = computeLoroReconnectDelayMs(state2.retryAttempt, {
|
|
79427
|
+
baseDelayMs: this.retryBaseDelayMs ?? readTimeoutEnv("LODY_LORO_MACHINE_FLOCK_RETRY_BASE_DELAY_MS", 1e3),
|
|
79428
|
+
maxDelayMs: this.retryMaxDelayMs ?? readTimeoutEnv("LODY_LORO_MACHINE_FLOCK_RETRY_MAX_DELAY_MS", 6e4),
|
|
79429
|
+
random: this.random
|
|
79430
|
+
});
|
|
79431
|
+
state2.retryAttempt += 1;
|
|
79432
|
+
state2.retryTimer = setTimeout(() => {
|
|
79433
|
+
state2.retryTimer = null;
|
|
79434
|
+
if (this.cleanedUp || !state2.dirty) {
|
|
79435
|
+
return;
|
|
79436
|
+
}
|
|
79437
|
+
void this.syncNow(state2.machineId, {
|
|
79438
|
+
reason: `retry:${reason}`,
|
|
79439
|
+
scheduleRetry: true
|
|
79440
|
+
});
|
|
79441
|
+
}, delayMs);
|
|
79442
|
+
this.logger.debug(`[${this.workspaceId}] Scheduled Machine Flock doc sync retry in ${delayMs}ms (machine=${state2.machineId} reason=${reason})`);
|
|
79443
|
+
}
|
|
79444
|
+
clearRetryTimer(state2) {
|
|
79445
|
+
if (!state2.retryTimer) {
|
|
79446
|
+
return;
|
|
79447
|
+
}
|
|
79448
|
+
clearTimeout(state2.retryTimer);
|
|
79449
|
+
state2.retryTimer = null;
|
|
79450
|
+
}
|
|
79451
|
+
getState(machineId) {
|
|
79452
|
+
const existing = this.states.get(machineId);
|
|
79453
|
+
if (existing) {
|
|
79454
|
+
return existing;
|
|
79455
|
+
}
|
|
79456
|
+
const state2 = {
|
|
79457
|
+
machineId,
|
|
79458
|
+
docId: getMachineFlockDocId(this.workspaceId, machineId),
|
|
79459
|
+
dirty: false,
|
|
79460
|
+
dirtyVersion: 0,
|
|
79461
|
+
retryAttempt: 0,
|
|
79462
|
+
retryTimer: null,
|
|
79463
|
+
activeSync: null,
|
|
79464
|
+
joinPromise: null,
|
|
79465
|
+
roomSub: null,
|
|
79466
|
+
detachRoomStatusListener: null
|
|
79467
|
+
};
|
|
79468
|
+
this.states.set(machineId, state2);
|
|
79469
|
+
return state2;
|
|
79470
|
+
}
|
|
79471
|
+
}
|
|
78958
79472
|
const SENSITIVE_QUERY_KEYS = /* @__PURE__ */ new Set([
|
|
78959
79473
|
"token",
|
|
78960
79474
|
"access_token",
|
|
@@ -98517,7 +99031,7 @@ ${value}`;
|
|
|
98517
99031
|
]);
|
|
98518
99032
|
return mergeAgentConfigs(loroRepoMetaConfigs, machineFlockConfigs);
|
|
98519
99033
|
}
|
|
98520
|
-
async function upsertMachineAgentConfig(repo, workspaceId, config2) {
|
|
99034
|
+
async function upsertMachineAgentConfig(repo, workspaceId, config2, options = {}) {
|
|
98521
99035
|
const handle = await repo.openFlockDoc(getMachineFlockDocId(workspaceId, config2.machineId));
|
|
98522
99036
|
const changed = writeMachineFlockRowToFlock(handle.flock, {
|
|
98523
99037
|
key: machineFlockKeys.agentConfig(config2.id),
|
|
@@ -98528,10 +99042,16 @@ ${value}`;
|
|
|
98528
99042
|
return;
|
|
98529
99043
|
}
|
|
98530
99044
|
await repo.flush();
|
|
98531
|
-
|
|
99045
|
+
if (options.sync) {
|
|
99046
|
+
options.sync.markMachineFlockDocDirty(config2.machineId, {
|
|
99047
|
+
reason: options.reason ?? "agent-config-upsert"
|
|
99048
|
+
});
|
|
99049
|
+
} else {
|
|
99050
|
+
await handle.syncOnce().catch(() => void 0);
|
|
99051
|
+
}
|
|
98532
99052
|
await deleteLoroRepoMetaAgentConfigIfPresent(repo, config2.id);
|
|
98533
99053
|
}
|
|
98534
|
-
async function deleteMachineAgentConfig(repo, workspaceId, config2) {
|
|
99054
|
+
async function deleteMachineAgentConfig(repo, workspaceId, config2, options = {}) {
|
|
98535
99055
|
const handle = await repo.openFlockDoc(getMachineFlockDocId(workspaceId, config2.machineId));
|
|
98536
99056
|
const changed = deleteMachineFlockRowFromFlock(handle.flock, machineFlockKeys.agentConfig(config2.id));
|
|
98537
99057
|
if (!changed) {
|
|
@@ -98539,7 +99059,13 @@ ${value}`;
|
|
|
98539
99059
|
return;
|
|
98540
99060
|
}
|
|
98541
99061
|
await repo.flush();
|
|
98542
|
-
|
|
99062
|
+
if (options.sync) {
|
|
99063
|
+
options.sync.markMachineFlockDocDirty(config2.machineId, {
|
|
99064
|
+
reason: options.reason ?? "agent-config-delete"
|
|
99065
|
+
});
|
|
99066
|
+
} else {
|
|
99067
|
+
await handle.syncOnce().catch(() => void 0);
|
|
99068
|
+
}
|
|
98543
99069
|
await deleteLoroRepoMetaAgentConfigIfPresent(repo, config2.id);
|
|
98544
99070
|
}
|
|
98545
99071
|
async function listMachineAgentConfigs(repo, workspaceId, machineIds) {
|
|
@@ -98735,11 +99261,21 @@ ${value}`;
|
|
|
98735
99261
|
this.initialMetaSyncCompleted = true;
|
|
98736
99262
|
}
|
|
98737
99263
|
});
|
|
99264
|
+
this.machineFlockSync = new MachineFlockSyncCoordinator({
|
|
99265
|
+
repo,
|
|
99266
|
+
workspaceId,
|
|
99267
|
+
logger: logger2
|
|
99268
|
+
});
|
|
99269
|
+
this.detachMachineFlockMetaRoomSyncedListener = this.connectionRecovery.onMetaRoomSynced((reason) => {
|
|
99270
|
+
this.machineFlockSync.retryDirtyNow(`meta-room-synced:${reason}`);
|
|
99271
|
+
});
|
|
98738
99272
|
}
|
|
98739
99273
|
sessions = /* @__PURE__ */ new Map();
|
|
98740
99274
|
machine = null;
|
|
98741
99275
|
machineExistenceWatcher = null;
|
|
98742
99276
|
connectionRecovery;
|
|
99277
|
+
machineFlockSync;
|
|
99278
|
+
detachMachineFlockMetaRoomSyncedListener = null;
|
|
98743
99279
|
initialMetaSyncCompleted = false;
|
|
98744
99280
|
initialMetaSyncPromise;
|
|
98745
99281
|
presenceRuntime;
|
|
@@ -98926,6 +99462,70 @@ ${value}`;
|
|
|
98926
99462
|
async waitUntilMetaSynced(options = {}) {
|
|
98927
99463
|
return await this.connectionRecovery.waitUntilMetaSynced(options);
|
|
98928
99464
|
}
|
|
99465
|
+
async syncMetaOrThrow(options = {}) {
|
|
99466
|
+
const reason = options.reason ?? "explicit-sync";
|
|
99467
|
+
const timeoutMs = options.timeoutMs ?? readTimeoutEnv("LODY_LORO_SYNC_META_TIMEOUT_MS", 2e4);
|
|
99468
|
+
const timeoutMessage = `Timeout waiting for workspace metadata sync (workspace=${this.workspaceId})`;
|
|
99469
|
+
try {
|
|
99470
|
+
await withTimeout$3(this.repo.sync({
|
|
99471
|
+
scope: "meta"
|
|
99472
|
+
}), timeoutMs, timeoutMessage);
|
|
99473
|
+
this.initialMetaSyncCompleted = true;
|
|
99474
|
+
} catch (error2) {
|
|
99475
|
+
throw new Error(`Workspace metadata sync failed (${reason}): ${formatErrorMessage(error2)}`, {
|
|
99476
|
+
cause: error2
|
|
99477
|
+
});
|
|
99478
|
+
}
|
|
99479
|
+
}
|
|
99480
|
+
async syncDocOrThrow(docId, options = {}) {
|
|
99481
|
+
const reason = options.reason ?? "explicit-sync";
|
|
99482
|
+
const timeoutMs = options.timeoutMs ?? readTimeoutEnv("LODY_LORO_SYNC_DOC_TIMEOUT_MS", 8e3);
|
|
99483
|
+
const timeoutMessage = `Timeout waiting for document sync (doc=${docId})`;
|
|
99484
|
+
try {
|
|
99485
|
+
await withTimeout$3(this.repo.sync({
|
|
99486
|
+
scope: "doc",
|
|
99487
|
+
docIds: [
|
|
99488
|
+
docId
|
|
99489
|
+
]
|
|
99490
|
+
}), timeoutMs, timeoutMessage);
|
|
99491
|
+
} catch (error2) {
|
|
99492
|
+
throw new Error(`Document sync failed for ${docId} (${reason}): ${formatErrorMessage(error2)}`, {
|
|
99493
|
+
cause: error2
|
|
99494
|
+
});
|
|
99495
|
+
}
|
|
99496
|
+
}
|
|
99497
|
+
async syncFlockDocOrThrow(flockDocId, options = {}) {
|
|
99498
|
+
const reason = options.reason ?? "explicit-sync";
|
|
99499
|
+
const timeoutMs = options.timeoutMs ?? readTimeoutEnv("LODY_LORO_SYNC_MACHINE_FLOCK_TIMEOUT_MS", 8e3);
|
|
99500
|
+
const timeoutMessage = `Timeout waiting for Flock document sync (doc=${flockDocId})`;
|
|
99501
|
+
try {
|
|
99502
|
+
await withTimeout$3(this.repo.sync({
|
|
99503
|
+
scope: "doc",
|
|
99504
|
+
flockDocIds: [
|
|
99505
|
+
flockDocId
|
|
99506
|
+
]
|
|
99507
|
+
}), timeoutMs, timeoutMessage);
|
|
99508
|
+
} catch (error2) {
|
|
99509
|
+
throw new Error(`Flock document sync failed for ${flockDocId} (${reason}): ${formatErrorMessage(error2)}`, {
|
|
99510
|
+
cause: error2
|
|
99511
|
+
});
|
|
99512
|
+
}
|
|
99513
|
+
}
|
|
99514
|
+
async syncMachineFlockDoc(machineId, options = {}) {
|
|
99515
|
+
return await this.machineFlockSync.syncNow(machineId, {
|
|
99516
|
+
...options,
|
|
99517
|
+
reason: options.reason ?? "explicit-sync",
|
|
99518
|
+
scheduleRetry: options.scheduleRetry ?? true
|
|
99519
|
+
});
|
|
99520
|
+
}
|
|
99521
|
+
markMachineFlockDocDirty(machineId, options = {}) {
|
|
99522
|
+
this.machineFlockSync.markDirty(machineId, options);
|
|
99523
|
+
}
|
|
99524
|
+
ensureMachineFlockDocJoined(machineId, options = {}) {
|
|
99525
|
+
void this.machineFlockSync.ensureJoined(machineId, options).catch((error2) => {
|
|
99526
|
+
this.logger.debug(`[${this.workspaceId}] Failed to join Machine Flock room (machine=${machineId} reason=${options.reason ?? "ensure-joined"}): ${formatErrorMessage(error2)}`);
|
|
99527
|
+
});
|
|
99528
|
+
}
|
|
98929
99529
|
async destroyRepo(options) {
|
|
98930
99530
|
const repoDestroyPromise = this.repo.destroy();
|
|
98931
99531
|
if (!options.fast) {
|
|
@@ -99038,6 +99638,9 @@ ${value}`;
|
|
|
99038
99638
|
cliType,
|
|
99039
99639
|
agentType,
|
|
99040
99640
|
env: {}
|
|
99641
|
+
}, {
|
|
99642
|
+
sync: this,
|
|
99643
|
+
reason: "agent-config-upsert"
|
|
99041
99644
|
});
|
|
99042
99645
|
return agentConfigId;
|
|
99043
99646
|
}
|
|
@@ -99045,7 +99648,7 @@ ${value}`;
|
|
|
99045
99648
|
}
|
|
99046
99649
|
async registerMachine(machineId, machine) {
|
|
99047
99650
|
if (!this.machine) {
|
|
99048
|
-
this.machine =
|
|
99651
|
+
this.machine = this.createMachineDocument(machineId);
|
|
99049
99652
|
await this.machine.init();
|
|
99050
99653
|
}
|
|
99051
99654
|
await this.machine.setMetaState({
|
|
@@ -99056,25 +99659,32 @@ ${value}`;
|
|
|
99056
99659
|
}
|
|
99057
99660
|
async updateRateLimits(machineId, cliType, limits) {
|
|
99058
99661
|
if (!this.machine) {
|
|
99059
|
-
this.machine =
|
|
99662
|
+
this.machine = this.createMachineDocument(machineId);
|
|
99060
99663
|
await this.machine.init();
|
|
99061
99664
|
}
|
|
99062
99665
|
await this.machine.updateRateLimits(cliType, limits);
|
|
99063
99666
|
}
|
|
99064
99667
|
async updateAcpCapabilities(machineId, cliType, agentType, modes, models, configOptions, availableCommands, sourceVersion) {
|
|
99065
99668
|
if (!this.machine) {
|
|
99066
|
-
this.machine =
|
|
99669
|
+
this.machine = this.createMachineDocument(machineId);
|
|
99067
99670
|
await this.machine.init();
|
|
99068
99671
|
}
|
|
99069
99672
|
await this.machine.updateAcpCapabilities(cliType, agentType, modes, models, configOptions, availableCommands, sourceVersion);
|
|
99070
99673
|
}
|
|
99071
99674
|
async getAcpCapabilities(machineId, cliType, agentType) {
|
|
99072
99675
|
if (!this.machine) {
|
|
99073
|
-
this.machine =
|
|
99676
|
+
this.machine = this.createMachineDocument(machineId);
|
|
99074
99677
|
await this.machine.init();
|
|
99075
99678
|
}
|
|
99076
99679
|
return this.machine.getAcpCapabilities(cliType, agentType);
|
|
99077
99680
|
}
|
|
99681
|
+
createMachineDocument(machineId) {
|
|
99682
|
+
return new MachineDocument(this.repo, this.workspaceId, machineId, (reason) => {
|
|
99683
|
+
this.markMachineFlockDocDirty(machineId, {
|
|
99684
|
+
reason
|
|
99685
|
+
});
|
|
99686
|
+
});
|
|
99687
|
+
}
|
|
99078
99688
|
async restoreMachineDocument(machineId) {
|
|
99079
99689
|
const machineRoomId = getMachineRoomId(machineId);
|
|
99080
99690
|
await this.repo.restoreDoc(machineRoomId);
|
|
@@ -99104,6 +99714,9 @@ ${value}`;
|
|
|
99104
99714
|
} catch (error2) {
|
|
99105
99715
|
this.logger.debug(`[${this.workspaceId}] Failed to stop Loro presence runtime: ${formatErrorMessage(error2)}`);
|
|
99106
99716
|
}
|
|
99717
|
+
this.detachMachineFlockMetaRoomSyncedListener?.();
|
|
99718
|
+
this.detachMachineFlockMetaRoomSyncedListener = null;
|
|
99719
|
+
await this.machineFlockSync.cleanUp();
|
|
99107
99720
|
await this.connectionRecovery.cleanUp();
|
|
99108
99721
|
for (const [sessionId, pending2] of this.pendingSessionDocs) {
|
|
99109
99722
|
try {
|
|
@@ -99988,10 +100601,11 @@ ${value}`;
|
|
|
99988
100601
|
return meta.meta;
|
|
99989
100602
|
};
|
|
99990
100603
|
class MachineDocument {
|
|
99991
|
-
constructor(repo, workspaceId, machineId) {
|
|
100604
|
+
constructor(repo, workspaceId, machineId, markMachineFlockDirty) {
|
|
99992
100605
|
this.repo = repo;
|
|
99993
100606
|
this.workspaceId = workspaceId;
|
|
99994
100607
|
this.machineId = machineId;
|
|
100608
|
+
this.markMachineFlockDirty = markMachineFlockDirty;
|
|
99995
100609
|
this.roomId = getMachineRoomId(this.machineId);
|
|
99996
100610
|
}
|
|
99997
100611
|
roomId;
|
|
@@ -100031,7 +100645,11 @@ ${value}`;
|
|
|
100031
100645
|
});
|
|
100032
100646
|
if (changed) {
|
|
100033
100647
|
await this.repo.flush();
|
|
100034
|
-
|
|
100648
|
+
if (this.markMachineFlockDirty) {
|
|
100649
|
+
this.markMachineFlockDirty("rate-limit-update");
|
|
100650
|
+
} else {
|
|
100651
|
+
await handle.syncOnce().catch(() => void 0);
|
|
100652
|
+
}
|
|
100035
100653
|
}
|
|
100036
100654
|
});
|
|
100037
100655
|
}
|
|
@@ -100064,7 +100682,11 @@ ${value}`;
|
|
|
100064
100682
|
});
|
|
100065
100683
|
if (changed) {
|
|
100066
100684
|
await this.repo.flush();
|
|
100067
|
-
|
|
100685
|
+
if (this.markMachineFlockDirty) {
|
|
100686
|
+
this.markMachineFlockDirty("acp-capability-update");
|
|
100687
|
+
} else {
|
|
100688
|
+
await handle.syncOnce().catch(() => void 0);
|
|
100689
|
+
}
|
|
100068
100690
|
}
|
|
100069
100691
|
}
|
|
100070
100692
|
async getAcpCapabilities(cliType, agentType) {
|
|
@@ -102156,7 +102778,9 @@ The file is not available yet and could not be downloaded; ask the user to resen
|
|
|
102156
102778
|
return remoteName;
|
|
102157
102779
|
}
|
|
102158
102780
|
async function probeGitHubRemoteAtRootPath(rootPath) {
|
|
102159
|
-
await
|
|
102781
|
+
if (!await isGitRepository(rootPath)) {
|
|
102782
|
+
return null;
|
|
102783
|
+
}
|
|
102160
102784
|
const remotes = await listGitRemotes(rootPath);
|
|
102161
102785
|
if (remotes.length === 0) return null;
|
|
102162
102786
|
const currentBranchRemote = await resolveCurrentBranchRemote(rootPath, remotes);
|
|
@@ -117765,18 +118389,6 @@ ${fallbackStderrTail}` : errorMessage;
|
|
|
117765
118389
|
function shouldScrubClaudeAuthEnv(cliType, agentType) {
|
|
117766
118390
|
return cliType === "builtin" && agentType === "claude" || cliType === "registry" && agentType === "claude-p";
|
|
117767
118391
|
}
|
|
117768
|
-
async function getStaticBuiltinAcpCapabilities(agentType) {
|
|
117769
|
-
if (!isBuiltinAgentType(agentType)) {
|
|
117770
|
-
return void 0;
|
|
117771
|
-
}
|
|
117772
|
-
const baseline = agentType === "claude" ? (await import("./chunks/baseline-config-CcYq1mUH.js")).getClaudeBaselineConfig() : (await import("./chunks/baseline-config-BPa_f3S0.js")).getCodexBaselineConfig();
|
|
117773
|
-
const configOptions = normalizeConfigOptions(baseline.configOptions);
|
|
117774
|
-
return {
|
|
117775
|
-
modes: baseline.modes,
|
|
117776
|
-
models: baseline.models,
|
|
117777
|
-
configOptions
|
|
117778
|
-
};
|
|
117779
|
-
}
|
|
117780
118392
|
function isSelectGroup$1(item) {
|
|
117781
118393
|
return typeof item === "object" && item !== null && "group" in item;
|
|
117782
118394
|
}
|
|
@@ -117854,7 +118466,7 @@ ${fallbackStderrTail}` : errorMessage;
|
|
|
117854
118466
|
async function fetchAcpCapabilities(cliType, agentType, logger2, env2, customAcp, runtimeOverrides, options = {}) {
|
|
117855
118467
|
const allowStaticBuiltinCapabilities = options.allowStaticBuiltinCapabilities ?? true;
|
|
117856
118468
|
if (allowStaticBuiltinCapabilities && cliType === "builtin" && !hasBuiltinRuntimeOverrideValues(runtimeOverrides)) {
|
|
117857
|
-
const staticCapabilities =
|
|
118469
|
+
const staticCapabilities = getStaticBuiltinAcpCapabilities(cliType, agentType, runtimeOverrides);
|
|
117858
118470
|
if (staticCapabilities) {
|
|
117859
118471
|
logger2.debug(`[acp-capabilities] Using static builtin capabilities (agentType=${agentType})`);
|
|
117860
118472
|
return staticCapabilities;
|
|
@@ -121377,7 +121989,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
|
|
|
121377
121989
|
...flockLocalProjects
|
|
121378
121990
|
};
|
|
121379
121991
|
}
|
|
121380
|
-
async function upsertMachineLocalProject(repo, workspaceId, machineId, project, nowMs2 = getServerNow()) {
|
|
121992
|
+
async function upsertMachineLocalProject(repo, workspaceId, machineId, project, nowMs2 = getServerNow(), options = {}) {
|
|
121381
121993
|
const handle = await repo.openFlockDoc(getMachineFlockDocId(workspaceId, machineId));
|
|
121382
121994
|
const changed = writeMachineFlockRowToFlock(handle.flock, {
|
|
121383
121995
|
key: machineFlockKeys.localProject(project.id),
|
|
@@ -121387,14 +121999,26 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
|
|
|
121387
121999
|
return;
|
|
121388
122000
|
}
|
|
121389
122001
|
await repo.flush();
|
|
121390
|
-
|
|
122002
|
+
if (options.sync) {
|
|
122003
|
+
options.sync.markMachineFlockDocDirty(machineId, {
|
|
122004
|
+
reason: options.reason ?? "local-project-upsert"
|
|
122005
|
+
});
|
|
122006
|
+
} else {
|
|
122007
|
+
await handle.syncOnce().catch(() => void 0);
|
|
122008
|
+
}
|
|
121391
122009
|
}
|
|
121392
|
-
async function removeMachineLocalProject(repo, workspaceId, machineId, localProjectId, nowMs2 = getServerNow()) {
|
|
122010
|
+
async function removeMachineLocalProject(repo, workspaceId, machineId, localProjectId, nowMs2 = getServerNow(), options = {}) {
|
|
121393
122011
|
const handle = await repo.openFlockDoc(getMachineFlockDocId(workspaceId, machineId));
|
|
121394
122012
|
const changed = deleteMachineFlockRowFromFlock(handle.flock, machineFlockKeys.localProject(localProjectId), nowMs2);
|
|
121395
122013
|
if (changed) {
|
|
121396
122014
|
await repo.flush();
|
|
121397
|
-
|
|
122015
|
+
if (options.sync) {
|
|
122016
|
+
options.sync.markMachineFlockDocDirty(machineId, {
|
|
122017
|
+
reason: options.reason ?? "local-project-remove"
|
|
122018
|
+
});
|
|
122019
|
+
} else {
|
|
122020
|
+
await handle.syncOnce().catch(() => void 0);
|
|
122021
|
+
}
|
|
121398
122022
|
}
|
|
121399
122023
|
const machineRoomId = getMachineRoomId(machineId);
|
|
121400
122024
|
const current2 = await repo.getDocMeta(machineRoomId);
|
|
@@ -133814,7 +134438,10 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
133814
134438
|
]))
|
|
133815
134439
|
}
|
|
133816
134440
|
}
|
|
133817
|
-
}, lastListedAt
|
|
134441
|
+
}, lastListedAt, {
|
|
134442
|
+
sync: this.manager,
|
|
134443
|
+
reason: "local-project-history-sync"
|
|
134444
|
+
});
|
|
133818
134445
|
});
|
|
133819
134446
|
return catalog;
|
|
133820
134447
|
}
|
|
@@ -139197,7 +139824,10 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
|
|
|
139197
139824
|
rootPath: entry.rootPath,
|
|
139198
139825
|
createdAtMs: previous?.createdAtMs ?? nowMs2,
|
|
139199
139826
|
lastOpenedAtMs: nowMs2
|
|
139200
|
-
}, nowMs2
|
|
139827
|
+
}, nowMs2, {
|
|
139828
|
+
sync: this.workspaceDocument,
|
|
139829
|
+
reason: "local-project-add"
|
|
139830
|
+
});
|
|
139201
139831
|
}
|
|
139202
139832
|
async authorizeLocalProjectRoot(args2) {
|
|
139203
139833
|
const access = await canUseMachineForCliToken({
|
|
@@ -148234,6 +148864,8 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
148234
148864
|
await next2;
|
|
148235
148865
|
}
|
|
148236
148866
|
}
|
|
148867
|
+
const BUILTIN_AGENT_CONFIG_INITIAL_RETRY_DELAY_MS = 1e4;
|
|
148868
|
+
const BUILTIN_AGENT_CONFIG_MAX_RETRY_DELAY_MS = 5 * 6e4;
|
|
148237
148869
|
class Lody {
|
|
148238
148870
|
constructor(options, documentManager) {
|
|
148239
148871
|
this.options = options;
|
|
@@ -148274,6 +148906,9 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
148274
148906
|
runtime;
|
|
148275
148907
|
supportRegistryAgentTypes;
|
|
148276
148908
|
cleanedUp = false;
|
|
148909
|
+
builtinAgentConfigRetryTimer;
|
|
148910
|
+
pendingBuiltinAgentConfigRetryCliTypes = /* @__PURE__ */ new Set();
|
|
148911
|
+
builtinAgentConfigRetryAttempt = 0;
|
|
148277
148912
|
static async create(options) {
|
|
148278
148913
|
const manager = await LoroDocumentManager.create(options.workspaceId, options.userId, () => options.token, options.logger);
|
|
148279
148914
|
return new Lody(options, manager);
|
|
@@ -148281,25 +148916,49 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
148281
148916
|
async start() {
|
|
148282
148917
|
void getLoginShellEnv();
|
|
148283
148918
|
await this.runtime.initialize();
|
|
148919
|
+
this.documentManager.ensureMachineFlockDocJoined(this.machineId, {
|
|
148920
|
+
reason: "lody-start"
|
|
148921
|
+
});
|
|
148284
148922
|
}
|
|
148285
148923
|
async registerAgent(cliTypes) {
|
|
148286
148924
|
await this.runtime.initialize();
|
|
148287
148925
|
if (this.documentManager.hasCompletedInitialMetaSync()) {
|
|
148288
|
-
await this.
|
|
148926
|
+
await this.ensureBuiltinAgentConfigsOrRetry(cliTypes);
|
|
148289
148927
|
} else {
|
|
148290
148928
|
this.logger.debug(`[agent-config] Initial meta sync is not complete for workspace ${this.workspaceId}; deferring builtin agent registration`);
|
|
148291
148929
|
void this.documentManager.waitForInitialMetaSync().then(async (completed) => {
|
|
148292
148930
|
if (!completed || this.cleanedUp) {
|
|
148293
148931
|
return;
|
|
148294
148932
|
}
|
|
148295
|
-
await this.
|
|
148933
|
+
await this.ensureBuiltinAgentConfigsOrRetry(cliTypes);
|
|
148296
148934
|
}).catch((error2) => {
|
|
148297
148935
|
this.logger.debug(`[agent-config] Deferred builtin agent registration failed: ${formatErrorMessage(error2)}`);
|
|
148298
148936
|
});
|
|
148299
148937
|
}
|
|
148300
148938
|
void this.refreshBuiltinCapabilities(cliTypes);
|
|
148301
148939
|
}
|
|
148940
|
+
async ensureBuiltinAgentConfigsOrRetry(cliTypes) {
|
|
148941
|
+
if (this.cleanedUp) {
|
|
148942
|
+
return;
|
|
148943
|
+
}
|
|
148944
|
+
const completed = await this.ensureBuiltinAgentConfigs(cliTypes);
|
|
148945
|
+
if (!completed) {
|
|
148946
|
+
this.scheduleBuiltinAgentConfigRetry(cliTypes);
|
|
148947
|
+
return;
|
|
148948
|
+
}
|
|
148949
|
+
this.builtinAgentConfigRetryAttempt = 0;
|
|
148950
|
+
}
|
|
148302
148951
|
async ensureBuiltinAgentConfigs(cliTypes) {
|
|
148952
|
+
if (cliTypes.length === 0) {
|
|
148953
|
+
return true;
|
|
148954
|
+
}
|
|
148955
|
+
const syncedMachineFlock = await this.documentManager.syncMachineFlockDoc(this.machineId, {
|
|
148956
|
+
reason: "builtin-agent-registration"
|
|
148957
|
+
});
|
|
148958
|
+
if (!syncedMachineFlock) {
|
|
148959
|
+
this.logger.debug(`[agent-config] Machine Flock sync is not complete for workspace ${this.workspaceId} machine ${this.machineId}; skipping builtin agent registration for this attempt`);
|
|
148960
|
+
return false;
|
|
148961
|
+
}
|
|
148303
148962
|
const builtinDisplayName = {
|
|
148304
148963
|
claude: "Claude Code",
|
|
148305
148964
|
codex: "Codex"
|
|
@@ -148310,6 +148969,40 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
148310
148969
|
await this.documentManager.createAgentConfig("builtin", cliType, this.machineId, builtinDisplayName[cliType]);
|
|
148311
148970
|
}
|
|
148312
148971
|
}
|
|
148972
|
+
return true;
|
|
148973
|
+
}
|
|
148974
|
+
scheduleBuiltinAgentConfigRetry(cliTypes) {
|
|
148975
|
+
if (cliTypes.length === 0 || this.cleanedUp) {
|
|
148976
|
+
return;
|
|
148977
|
+
}
|
|
148978
|
+
for (const cliType of cliTypes) {
|
|
148979
|
+
this.pendingBuiltinAgentConfigRetryCliTypes.add(cliType);
|
|
148980
|
+
}
|
|
148981
|
+
if (this.builtinAgentConfigRetryTimer) {
|
|
148982
|
+
return;
|
|
148983
|
+
}
|
|
148984
|
+
const delayMs = this.nextBuiltinAgentConfigRetryDelayMs();
|
|
148985
|
+
this.logger.debug(`[agent-config] Scheduling builtin agent registration retry in ${delayMs}ms for workspace ${this.workspaceId} machine ${this.machineId}`);
|
|
148986
|
+
this.builtinAgentConfigRetryTimer = setTimeout(() => {
|
|
148987
|
+
this.builtinAgentConfigRetryTimer = void 0;
|
|
148988
|
+
if (this.cleanedUp) {
|
|
148989
|
+
this.pendingBuiltinAgentConfigRetryCliTypes.clear();
|
|
148990
|
+
return;
|
|
148991
|
+
}
|
|
148992
|
+
const retryCliTypes = [
|
|
148993
|
+
...this.pendingBuiltinAgentConfigRetryCliTypes
|
|
148994
|
+
];
|
|
148995
|
+
this.pendingBuiltinAgentConfigRetryCliTypes.clear();
|
|
148996
|
+
void this.ensureBuiltinAgentConfigsOrRetry(retryCliTypes).catch((error2) => {
|
|
148997
|
+
this.logger.debug(`[agent-config] Retried builtin agent registration failed: ${formatErrorMessage(error2)}`);
|
|
148998
|
+
});
|
|
148999
|
+
}, delayMs);
|
|
149000
|
+
this.builtinAgentConfigRetryTimer.unref?.();
|
|
149001
|
+
}
|
|
149002
|
+
nextBuiltinAgentConfigRetryDelayMs() {
|
|
149003
|
+
const multiplier = 2 ** Math.min(this.builtinAgentConfigRetryAttempt, 5);
|
|
149004
|
+
this.builtinAgentConfigRetryAttempt += 1;
|
|
149005
|
+
return Math.min(BUILTIN_AGENT_CONFIG_INITIAL_RETRY_DELAY_MS * multiplier, BUILTIN_AGENT_CONFIG_MAX_RETRY_DELAY_MS);
|
|
148313
149006
|
}
|
|
148314
149007
|
async refreshBuiltinCapabilities(cliTypes) {
|
|
148315
149008
|
for (const cliType of cliTypes) {
|
|
@@ -148340,6 +149033,12 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
148340
149033
|
}
|
|
148341
149034
|
cleanup = async () => {
|
|
148342
149035
|
this.cleanedUp = true;
|
|
149036
|
+
if (this.builtinAgentConfigRetryTimer) {
|
|
149037
|
+
clearTimeout(this.builtinAgentConfigRetryTimer);
|
|
149038
|
+
this.builtinAgentConfigRetryTimer = void 0;
|
|
149039
|
+
}
|
|
149040
|
+
this.pendingBuiltinAgentConfigRetryCliTypes.clear();
|
|
149041
|
+
this.builtinAgentConfigRetryAttempt = 0;
|
|
148343
149042
|
return await this.runtime.cleanup();
|
|
148344
149043
|
};
|
|
148345
149044
|
async dispatchLocalControl(message) {
|
|
@@ -150549,10 +151248,16 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
150549
151248
|
rootPath: entry.rootPath,
|
|
150550
151249
|
createdAtMs: previous?.createdAtMs ?? nowMs2,
|
|
150551
151250
|
lastOpenedAtMs: nowMs2
|
|
150552
|
-
}, nowMs2
|
|
151251
|
+
}, nowMs2, {
|
|
151252
|
+
sync: runtime.lody.documentManager,
|
|
151253
|
+
reason: "local-project-add"
|
|
151254
|
+
});
|
|
150553
151255
|
}
|
|
150554
151256
|
async removeProjectMetaInWorkspace(runtime, localProjectId) {
|
|
150555
|
-
await removeMachineLocalProject(runtime.lody.documentManager.repo, runtime.workspace.id, this.machineId, localProjectId
|
|
151257
|
+
await removeMachineLocalProject(runtime.lody.documentManager.repo, runtime.workspace.id, this.machineId, localProjectId, void 0, {
|
|
151258
|
+
sync: runtime.lody.documentManager,
|
|
151259
|
+
reason: "local-project-delete"
|
|
151260
|
+
});
|
|
150556
151261
|
}
|
|
150557
151262
|
async listProjectsByWorkspace() {
|
|
150558
151263
|
const groups = [];
|
|
@@ -177422,6 +178127,29 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
|
|
|
177422
178127
|
throw new Error(`Workspace metadata changes were not confirmed by Loro Streams (${reason}). Retry the command after checking network connectivity.`);
|
|
177423
178128
|
}
|
|
177424
178129
|
}
|
|
178130
|
+
function buildOfflineHint(error2) {
|
|
178131
|
+
return new Error(`${formatErrorMessage(error2)} Use --offline to read the local cache without syncing.`, {
|
|
178132
|
+
cause: error2
|
|
178133
|
+
});
|
|
178134
|
+
}
|
|
178135
|
+
async function syncWorkspaceMetaForRead(manager, reason) {
|
|
178136
|
+
try {
|
|
178137
|
+
await manager.syncMetaOrThrow({
|
|
178138
|
+
reason
|
|
178139
|
+
});
|
|
178140
|
+
} catch (error2) {
|
|
178141
|
+
throw buildOfflineHint(error2);
|
|
178142
|
+
}
|
|
178143
|
+
}
|
|
178144
|
+
async function syncDocForRead(manager, docId, reason) {
|
|
178145
|
+
try {
|
|
178146
|
+
await manager.syncDocOrThrow(docId, {
|
|
178147
|
+
reason
|
|
178148
|
+
});
|
|
178149
|
+
} catch (error2) {
|
|
178150
|
+
throw buildOfflineHint(error2);
|
|
178151
|
+
}
|
|
178152
|
+
}
|
|
177425
178153
|
async function listAliveRoomIds(manager, predicate) {
|
|
177426
178154
|
const scanner = manager.repo.getMeta();
|
|
177427
178155
|
if (!scanner) {
|
|
@@ -177600,16 +178328,19 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
|
|
|
177600
178328
|
await action();
|
|
177601
178329
|
await exitOneShotCommand(0);
|
|
177602
178330
|
} catch (error2) {
|
|
178331
|
+
const commandError = error2 && typeof error2 === "object" ? error2 : void 0;
|
|
177603
178332
|
const message = formatErrorMessage(error2);
|
|
177604
|
-
if (
|
|
177605
|
-
|
|
177606
|
-
|
|
177607
|
-
|
|
177608
|
-
|
|
177609
|
-
|
|
177610
|
-
|
|
178333
|
+
if (commandError?.suppressCommandErrorOutput !== true) {
|
|
178334
|
+
if (options.json || options.jsonl) {
|
|
178335
|
+
printJson({
|
|
178336
|
+
ok: false,
|
|
178337
|
+
error: message
|
|
178338
|
+
});
|
|
178339
|
+
} else {
|
|
178340
|
+
getLogger(loggerName).error(message);
|
|
178341
|
+
}
|
|
177611
178342
|
}
|
|
177612
|
-
await exitOneShotCommand(1);
|
|
178343
|
+
await exitOneShotCommand(commandError?.exitCode ?? 1);
|
|
177613
178344
|
}
|
|
177614
178345
|
}
|
|
177615
178346
|
var debug_1;
|
|
@@ -180339,16 +181070,28 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
|
|
|
180339
181070
|
configOptionValues
|
|
180340
181071
|
};
|
|
180341
181072
|
}
|
|
180342
|
-
const agentConfigListCommand = new Command("list").description("List agent configs in a workspace").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--json", "Print JSON output").option("--debug", "Enable debug output").action(async (options) => {
|
|
181073
|
+
const agentConfigListCommand = new Command("list").description("List agent configs in a workspace").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--machine <idOrName>", "Only include configs for one machine").option("--json", "Print JSON output").option("--debug", "Enable debug output").action(async (options) => {
|
|
180343
181074
|
await runOneShotCommand("agent-config", options, async () => {
|
|
180344
181075
|
const auth = getAuthContextOrThrow$1("agent-config");
|
|
180345
181076
|
const workspace = await resolveWorkspaceOrThrow$1(auth, options.workspace);
|
|
180346
181077
|
await withWorkspaceManager$1(auth, workspace, "agent-config", async (manager) => {
|
|
180347
|
-
const
|
|
181078
|
+
const machineSelector = normalizeCliValue(options.machine);
|
|
181079
|
+
let machineId;
|
|
181080
|
+
if (machineSelector) {
|
|
181081
|
+
const machine = resolveMachineOrThrow(await listMachineMetasForWorkspace(manager), {
|
|
181082
|
+
selector: machineSelector,
|
|
181083
|
+
authMachineId: auth.machineId
|
|
181084
|
+
});
|
|
181085
|
+
machineId = machine.id;
|
|
181086
|
+
}
|
|
181087
|
+
const configs = (await listAgentConfigsForWorkspace$1(manager, workspace.id)).filter((config2) => machineId === void 0 || config2.machineId === machineId);
|
|
180348
181088
|
if (options.json) {
|
|
180349
181089
|
printJson({
|
|
180350
181090
|
ok: true,
|
|
180351
181091
|
workspaceId: workspace.id,
|
|
181092
|
+
...machineId ? {
|
|
181093
|
+
machineId
|
|
181094
|
+
} : {},
|
|
180352
181095
|
agentConfigs: configs.map(toAgentConfigOutput)
|
|
180353
181096
|
});
|
|
180354
181097
|
return;
|
|
@@ -180805,13 +181548,21 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
|
|
|
180805
181548
|
}
|
|
180806
181549
|
throw new Error(`Agent config not found: ${normalizedSelector}. Candidates: ${formatAgentConfigCandidates(configs)}`);
|
|
180807
181550
|
}
|
|
181551
|
+
function resolveCreateAgentSelector(options) {
|
|
181552
|
+
const agent2 = normalizeCliValue(options.agent);
|
|
181553
|
+
const agentConfig = normalizeCliValue(options.agentConfig);
|
|
181554
|
+
if (agent2 && agentConfig && agent2 !== agentConfig) {
|
|
181555
|
+
throw new Error("Pass either --agent or --agent-config, not both.");
|
|
181556
|
+
}
|
|
181557
|
+
return agentConfig ?? agent2;
|
|
181558
|
+
}
|
|
180808
181559
|
function buildAgentPrompt(prompt2, agentPrompt = "") {
|
|
180809
181560
|
return [
|
|
180810
181561
|
agentPrompt,
|
|
180811
181562
|
prompt2
|
|
180812
181563
|
].filter((part) => part?.trim()).join("\n\n");
|
|
180813
181564
|
}
|
|
180814
|
-
function parsePositiveIntOption(value) {
|
|
181565
|
+
function parsePositiveIntOption$1(value) {
|
|
180815
181566
|
const parsed = Number.parseInt(value, 10);
|
|
180816
181567
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
180817
181568
|
throw new Error(`Invalid numeric value: ${value}`);
|
|
@@ -180898,6 +181649,9 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
|
|
|
180898
181649
|
return entries.map((entry) => `[${entry.role}] ${entry.timestamp} ${entry.id}
|
|
180899
181650
|
${entry.text}`).join("\n\n");
|
|
180900
181651
|
}
|
|
181652
|
+
function renderAssistantTurnCompletion(content) {
|
|
181653
|
+
return extractTranscriptText(content, "assistant") ?? "No visible assistant reply found.";
|
|
181654
|
+
}
|
|
180901
181655
|
async function readStdinText() {
|
|
180902
181656
|
const chunks = [];
|
|
180903
181657
|
return await new Promise((resolve2, reject) => {
|
|
@@ -181198,15 +181952,22 @@ ${entry.text}`).join("\n\n");
|
|
|
181198
181952
|
const effectiveSelector = normalizeCliValue(selector) ?? normalizeCliValue(process.env.LODY_WORKSPACE_ID);
|
|
181199
181953
|
return selectWorkspaceSummary(workspaces, effectiveSelector);
|
|
181200
181954
|
}
|
|
181201
|
-
async function resolveWorkspaceForSessionOrThrow(auth, sessionId,
|
|
181955
|
+
async function resolveWorkspaceForSessionOrThrow(auth, sessionId, options) {
|
|
181202
181956
|
const workspaces = await listWorkspacesForToken(auth.token);
|
|
181957
|
+
const selector = typeof options === "string" ? options : options?.workspace;
|
|
181958
|
+
const shouldSync = typeof options === "object" && options.offline !== true;
|
|
181959
|
+
const syncReason = typeof options === "object" ? options.reason : void 0;
|
|
181203
181960
|
const effectiveSelector = normalizeCliValue(selector) ?? normalizeCliValue(process.env.LODY_WORKSPACE_ID);
|
|
181961
|
+
const sessionExistsInWorkspace = async (workspace) => await withWorkspaceManager(auth, workspace, async (manager) => {
|
|
181962
|
+
if (shouldSync) {
|
|
181963
|
+
await syncWorkspaceMetaForRead(manager, syncReason ?? `session.resolve:${sessionId}:${workspace.id}`);
|
|
181964
|
+
}
|
|
181965
|
+
const raw2 = await manager.repo.getDocMeta(getSessionRoomId(sessionId));
|
|
181966
|
+
return !!raw2?.meta && !isLoroRepoDocDeleted(raw2);
|
|
181967
|
+
});
|
|
181204
181968
|
if (effectiveSelector) {
|
|
181205
181969
|
const workspace = selectWorkspaceSummary(workspaces, effectiveSelector);
|
|
181206
|
-
const exists = await
|
|
181207
|
-
const raw2 = await manager.repo.getDocMeta(getSessionRoomId(sessionId));
|
|
181208
|
-
return !!raw2?.meta && !isLoroRepoDocDeleted(raw2);
|
|
181209
|
-
});
|
|
181970
|
+
const exists = await sessionExistsInWorkspace(workspace);
|
|
181210
181971
|
if (!exists) {
|
|
181211
181972
|
throw new Error(`Session not found in workspace ${workspace.id}: ${sessionId}`);
|
|
181212
181973
|
}
|
|
@@ -181214,10 +181975,7 @@ ${entry.text}`).join("\n\n");
|
|
|
181214
181975
|
}
|
|
181215
181976
|
if (workspaces.length === 1) {
|
|
181216
181977
|
const workspace = workspaces[0];
|
|
181217
|
-
const exists = await
|
|
181218
|
-
const raw2 = await manager.repo.getDocMeta(getSessionRoomId(sessionId));
|
|
181219
|
-
return !!raw2?.meta && !isLoroRepoDocDeleted(raw2);
|
|
181220
|
-
});
|
|
181978
|
+
const exists = await sessionExistsInWorkspace(workspace);
|
|
181221
181979
|
if (!exists) {
|
|
181222
181980
|
throw new Error(`Session not found: ${sessionId}`);
|
|
181223
181981
|
}
|
|
@@ -181225,10 +181983,7 @@ ${entry.text}`).join("\n\n");
|
|
|
181225
181983
|
}
|
|
181226
181984
|
const matches = [];
|
|
181227
181985
|
for (const workspace of workspaces) {
|
|
181228
|
-
const exists = await
|
|
181229
|
-
const raw2 = await manager.repo.getDocMeta(getSessionRoomId(sessionId));
|
|
181230
|
-
return !!raw2?.meta && !isLoroRepoDocDeleted(raw2);
|
|
181231
|
-
});
|
|
181986
|
+
const exists = await sessionExistsInWorkspace(workspace);
|
|
181232
181987
|
if (exists) {
|
|
181233
181988
|
matches.push(workspace);
|
|
181234
181989
|
}
|
|
@@ -181241,6 +181996,13 @@ ${entry.text}`).join("\n\n");
|
|
|
181241
181996
|
}
|
|
181242
181997
|
return matches[0];
|
|
181243
181998
|
}
|
|
181999
|
+
async function syncSessionReadData(manager, sessionId, offline, reason) {
|
|
182000
|
+
if (offline === true) {
|
|
182001
|
+
return;
|
|
182002
|
+
}
|
|
182003
|
+
await syncWorkspaceMetaForRead(manager, `${reason}:meta`);
|
|
182004
|
+
await syncDocForRead(manager, getSessionRoomId(sessionId), `${reason}:doc`);
|
|
182005
|
+
}
|
|
181244
182006
|
async function resolveSessionMetaOrThrow(manager, sessionId) {
|
|
181245
182007
|
const raw2 = await manager.repo.getDocMeta(getSessionRoomId(sessionId));
|
|
181246
182008
|
if (!raw2?.meta || isLoroRepoDocDeleted(raw2)) {
|
|
@@ -181575,6 +182337,37 @@ ${entry.text}`).join("\n\n");
|
|
|
181575
182337
|
messageQueueCount: docState?.mq?.length ?? 0
|
|
181576
182338
|
};
|
|
181577
182339
|
}
|
|
182340
|
+
async function buildSessionStatusResult(workspace, manager, sessionId) {
|
|
182341
|
+
const session = await resolveSessionMetaOrThrow(manager, sessionId);
|
|
182342
|
+
const sessionDoc = await manager.getOrCreateSessionDoc(sessionId);
|
|
182343
|
+
const history = await sessionDoc.getHistory();
|
|
182344
|
+
const assistantTurnId = resolveActiveAssistantTurnId(history);
|
|
182345
|
+
return {
|
|
182346
|
+
workspace,
|
|
182347
|
+
sessionId,
|
|
182348
|
+
status: session.status,
|
|
182349
|
+
machineId: session.machineId,
|
|
182350
|
+
agent: {
|
|
182351
|
+
cliType: session.cliType,
|
|
182352
|
+
agentType: session.agentType,
|
|
182353
|
+
...session.agentConfigId ? {
|
|
182354
|
+
agentConfigId: session.agentConfigId
|
|
182355
|
+
} : {}
|
|
182356
|
+
},
|
|
182357
|
+
archived: session.isArchived === true,
|
|
182358
|
+
...assistantTurnId ? {
|
|
182359
|
+
activeTurn: {
|
|
182360
|
+
assistantTurnId,
|
|
182361
|
+
...session.processingUserMsgId ? {
|
|
182362
|
+
processingUserMsgId: session.processingUserMsgId
|
|
182363
|
+
} : {},
|
|
182364
|
+
...session.latestUserMsgId ? {
|
|
182365
|
+
latestUserMsgId: session.latestUserMsgId
|
|
182366
|
+
} : {}
|
|
182367
|
+
}
|
|
182368
|
+
} : {}
|
|
182369
|
+
};
|
|
182370
|
+
}
|
|
181578
182371
|
function printHumanSessionList(sessions) {
|
|
181579
182372
|
if (sessions.length === 0) {
|
|
181580
182373
|
console.log("No sessions found.");
|
|
@@ -181622,6 +182415,16 @@ ${entry.text}`).join("\n\n");
|
|
|
181622
182415
|
console.log(`createdAt: ${session.createdAt}`);
|
|
181623
182416
|
console.log(`lastHistoryAt: ${result.latestHistoryAt ?? "-"}`);
|
|
181624
182417
|
}
|
|
182418
|
+
function printHumanSessionStatus(result) {
|
|
182419
|
+
console.log(`id: ${result.sessionId}`);
|
|
182420
|
+
console.log(`workspace: ${result.workspace.slug ?? result.workspace.id}`);
|
|
182421
|
+
console.log(`machine: ${result.machineId}`);
|
|
182422
|
+
console.log(`status: ${result.status?.type ?? "unknown"}`);
|
|
182423
|
+
console.log(`archived: ${result.archived ? "yes" : "no"}`);
|
|
182424
|
+
console.log(`agent: ${result.agent.cliType}/${result.agent.agentType}`);
|
|
182425
|
+
console.log(`agentConfigId: ${result.agent.agentConfigId ?? "-"}`);
|
|
182426
|
+
console.log(`activeTurn: ${result.activeTurn?.assistantTurnId ?? "-"}`);
|
|
182427
|
+
}
|
|
181625
182428
|
async function runSessionCommand(options, action) {
|
|
181626
182429
|
if (options.debug) {
|
|
181627
182430
|
rootLogger.setDebug(true);
|
|
@@ -181680,7 +182483,7 @@ ${entry.text}`).join("\n\n");
|
|
|
181680
182483
|
process.exit(code2);
|
|
181681
182484
|
}
|
|
181682
182485
|
}
|
|
181683
|
-
const sessionCreateCommand = new Command("create").description("Create a new session on the current machine").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--agent-config <idOrName>", "Agent config id or name").option("--title <title>", "Session title").option("--repo <owner/repo>", "GitHub repository to attach").option("--local-project <id|name|path>", "Local project id, name, or root path").option("--worktree", "Create an isolated git worktree for --local-project").option("--branch <name>", "Git branch to use for GitHub repos or local git projects").option("--mode <modeId>", "ACP mode override").option("--model <modelId>", "ACP model override").option("--env <keyValue>", "Deprecated per-session env override; configure env on the agent config instead", collectListOption, []).option("--prompt <text>", "Prompt text").option("--prompt-file <path>", "Read prompt text from file, or - for stdin").option("--json", "Print JSON output").option("--jsonl", "Print JSON Lines output").option("--timeout <seconds>", "Wait timeout in seconds for
|
|
182486
|
+
const sessionCreateCommand = new Command("create").description("Create a new session on the current machine").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--agent <idOrName>", "Agent config id or name").option("--agent-config <idOrName>", "Agent config id or name").option("--title <title>", "Session title").option("--repo <owner/repo>", "GitHub repository to attach").option("--local-project <id|name|path>", "Local project id, name, or root path").option("--worktree", "Create an isolated git worktree for --local-project").option("--branch <name>", "Git branch to use for GitHub repos or local git projects").option("--mode <modeId>", "ACP mode override").option("--model <modelId>", "ACP model override").option("--env <keyValue>", "Deprecated per-session env override; configure env on the agent config instead", collectListOption, []).option("--prompt <text>", "Prompt text").option("--prompt-file <path>", "Read prompt text from file, or - for stdin").option("--json", "Print JSON output").option("--jsonl", "Print JSON Lines output").option("--wait", "Wait for the assistant turn to complete before exiting").option("--timeout <seconds>", "Wait timeout in seconds for --wait, --json, and --jsonl", parsePositiveIntOption$1).option("--debug", "Enable debug output").argument("[prompt]", "Prompt text").action(async (promptArg, options) => {
|
|
181684
182487
|
await runSessionCommand(options, async () => {
|
|
181685
182488
|
const outputMode = resolveStructuredOutputMode(options);
|
|
181686
182489
|
const createStartMs = Date.now();
|
|
@@ -181693,12 +182496,16 @@ ${entry.text}`).join("\n\n");
|
|
|
181693
182496
|
const prompt2 = await readPromptText(options, promptArg);
|
|
181694
182497
|
await ensureLocalRuntimeAvailable(auth.machineId, workspace.id);
|
|
181695
182498
|
await withWorkspaceManager(auth, workspace, async (manager) => {
|
|
181696
|
-
const
|
|
182499
|
+
const agentSelector = resolveCreateAgentSelector(options);
|
|
182500
|
+
const agentConfig = await resolveAgentConfigOrThrow(manager, workspace.id, agentSelector);
|
|
181697
182501
|
const dispatchConfig = resolveTurnDispatchConfig({
|
|
181698
182502
|
mode: options.mode,
|
|
181699
182503
|
model: options.model
|
|
181700
182504
|
});
|
|
181701
|
-
const result = await createSessionResult(auth, workspace, manager, prompt2, options, agentConfig, dispatchConfig, outputMode === "human" ?
|
|
182505
|
+
const result = await createSessionResult(auth, workspace, manager, prompt2, options, agentConfig, dispatchConfig, outputMode === "human" ? options.wait === true ? {
|
|
182506
|
+
outputMode: "json",
|
|
182507
|
+
timeoutMs: resolveStructuredOutputTimeoutMs(options.timeout)
|
|
182508
|
+
} : void 0 : {
|
|
181702
182509
|
outputMode,
|
|
181703
182510
|
timeoutMs: resolveStructuredOutputTimeoutMs(options.timeout),
|
|
181704
182511
|
onEvent: outputMode === "jsonl" ? (event) => printJson(event) : void 0
|
|
@@ -181749,13 +182556,29 @@ ${entry.text}`).join("\n\n");
|
|
|
181749
182556
|
}
|
|
181750
182557
|
return;
|
|
181751
182558
|
}
|
|
182559
|
+
console.log(result.sessionId);
|
|
182560
|
+
if (options.wait === true) {
|
|
182561
|
+
const completionPromise = result.completionPromise;
|
|
182562
|
+
if (!completionPromise) {
|
|
182563
|
+
throw new Error("Missing completion promise for session create --wait output.");
|
|
182564
|
+
}
|
|
182565
|
+
const completedTurn = await completionPromise;
|
|
182566
|
+
captureSessionCommandEvent("session_create_succeeded", {
|
|
182567
|
+
output_mode: outputMode,
|
|
182568
|
+
turn_duration_ms: completedTurn.durationMs
|
|
182569
|
+
}, {
|
|
182570
|
+
distinctId: auth.machineId
|
|
182571
|
+
});
|
|
182572
|
+
console.log("");
|
|
182573
|
+
console.log(renderAssistantTurnCompletion(completedTurn.content));
|
|
182574
|
+
return;
|
|
182575
|
+
}
|
|
181752
182576
|
captureSessionCommandEvent("session_create_succeeded", {
|
|
181753
182577
|
output_mode: outputMode,
|
|
181754
182578
|
turn_duration_ms: Date.now() - createStartMs
|
|
181755
182579
|
}, {
|
|
181756
182580
|
distinctId: auth.machineId
|
|
181757
182581
|
});
|
|
181758
|
-
console.log(result.sessionId);
|
|
181759
182582
|
});
|
|
181760
182583
|
} catch (error2) {
|
|
181761
182584
|
captureSessionCommandEvent("session_create_failed", {
|
|
@@ -181766,7 +182589,7 @@ ${entry.text}`).join("\n\n");
|
|
|
181766
182589
|
}
|
|
181767
182590
|
});
|
|
181768
182591
|
});
|
|
181769
|
-
const sessionChatCommand = new Command("chat").description("Send a new user prompt to an existing session on the current machine").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--mode <modeId>", "ACP mode override").option("--model <modelId>", "ACP model override").option("--prompt <text>", "Prompt text").option("--prompt-file <path>", "Read prompt text from file, or - for stdin").option("--json", "Print JSON output").option("--jsonl", "Print JSON Lines output").option("--timeout <seconds>", "Wait timeout in seconds for
|
|
182592
|
+
const sessionChatCommand = new Command("chat").description("Send a new user prompt to an existing session on the current machine").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--mode <modeId>", "ACP mode override").option("--model <modelId>", "ACP model override").option("--prompt <text>", "Prompt text").option("--prompt-file <path>", "Read prompt text from file, or - for stdin").option("--json", "Print JSON output").option("--jsonl", "Print JSON Lines output").option("--wait", "Wait for the assistant turn to complete before exiting").option("--timeout <seconds>", "Wait timeout in seconds for --wait, --json, and --jsonl", parsePositiveIntOption$1).option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").argument("[prompt]", "Prompt text").action(async (sessionIdArg, promptArg, options) => {
|
|
181770
182593
|
await runSessionCommand(options, async () => {
|
|
181771
182594
|
const outputMode = resolveStructuredOutputMode(options);
|
|
181772
182595
|
const auth = getAuthContextOrThrow();
|
|
@@ -181813,15 +182636,16 @@ ${entry.text}`).join("\n\n");
|
|
|
181813
182636
|
configOptionValues: dispatchConfig.configOptionValues,
|
|
181814
182637
|
resume: session.acpSessionId ?? void 0
|
|
181815
182638
|
}));
|
|
181816
|
-
const
|
|
181817
|
-
const
|
|
182639
|
+
const shouldWaitForCompletion = outputMode !== "human" || options.wait === true;
|
|
182640
|
+
const completionAbortController = shouldWaitForCompletion ? new AbortController() : void 0;
|
|
182641
|
+
const completionPromise = shouldWaitForCompletion ? waitForTurnCompletion({
|
|
181818
182642
|
sessionDoc,
|
|
181819
182643
|
userTurnId,
|
|
181820
|
-
outputMode,
|
|
182644
|
+
outputMode: outputMode === "human" ? "json" : outputMode,
|
|
181821
182645
|
timeoutMs: resolveStructuredOutputTimeoutMs(options.timeout),
|
|
181822
182646
|
signal: completionAbortController?.signal,
|
|
181823
182647
|
onEvent: outputMode === "jsonl" ? (event) => printJson(event) : void 0
|
|
181824
|
-
});
|
|
182648
|
+
}) : void 0;
|
|
181825
182649
|
try {
|
|
181826
182650
|
await updateSessionActivityTimestampsBestEffort(manager, sessionId);
|
|
181827
182651
|
await ensureSessionDocSynced(sessionDoc, `session.chat:${sessionId}:${userTurnId}`);
|
|
@@ -181862,6 +182686,18 @@ ${entry.text}`).join("\n\n");
|
|
|
181862
182686
|
}
|
|
181863
182687
|
return;
|
|
181864
182688
|
}
|
|
182689
|
+
if (options.wait === true) {
|
|
182690
|
+
try {
|
|
182691
|
+
if (!completionPromise) {
|
|
182692
|
+
throw new Error("Missing completion promise for session chat --wait output.");
|
|
182693
|
+
}
|
|
182694
|
+
const completedTurn = await completionPromise;
|
|
182695
|
+
console.log(renderAssistantTurnCompletion(completedTurn.content));
|
|
182696
|
+
} catch (error2) {
|
|
182697
|
+
throw buildStructuredWaitError("json", sessionId, userTurnId, error2);
|
|
182698
|
+
}
|
|
182699
|
+
return;
|
|
182700
|
+
}
|
|
181865
182701
|
console.log(userTurnId);
|
|
181866
182702
|
});
|
|
181867
182703
|
});
|
|
@@ -181903,11 +182739,14 @@ ${entry.text}`).join("\n\n");
|
|
|
181903
182739
|
});
|
|
181904
182740
|
});
|
|
181905
182741
|
});
|
|
181906
|
-
const sessionListCommand = new Command("list").description("List sessions in a workspace").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--archived", "Only include archived sessions").option("--all", "Include active and archived sessions").option("--limit <count>", "Maximum number of sessions to print", parsePositiveIntOption).option("--json", "Print JSON output").option("--debug", "Enable debug output").action(async (options) => {
|
|
182742
|
+
const sessionListCommand = new Command("list").description("List sessions in a workspace").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--archived", "Only include archived sessions").option("--all", "Include active and archived sessions").option("--limit <count>", "Maximum number of sessions to print", parsePositiveIntOption$1).option("--offline", "Read the local cache without syncing first").option("--json", "Print JSON output").option("--debug", "Enable debug output").action(async (options) => {
|
|
181907
182743
|
await runSessionCommand(options, async () => {
|
|
181908
182744
|
const auth = getAuthContextOrThrow();
|
|
181909
182745
|
const workspace = await resolveWorkspaceOrThrow(auth, options.workspace);
|
|
181910
182746
|
await withWorkspaceManager(auth, workspace, async (manager) => {
|
|
182747
|
+
if (options.offline !== true) {
|
|
182748
|
+
await syncWorkspaceMetaForRead(manager, `session.list:${workspace.id}`);
|
|
182749
|
+
}
|
|
181911
182750
|
const sessions = sortSessionMetas(filterSessionMetas(await listSessionMetasForWorkspace(manager), {
|
|
181912
182751
|
archivedOnly: options.archived,
|
|
181913
182752
|
includeAll: options.all
|
|
@@ -181925,7 +182764,7 @@ ${entry.text}`).join("\n\n");
|
|
|
181925
182764
|
});
|
|
181926
182765
|
});
|
|
181927
182766
|
});
|
|
181928
|
-
const sessionHistoryCommand = new Command("history").description("Read visible session transcript history").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--limit <count>", "Maximum number of transcript turns to print", parsePositiveIntOption).option("--all", "Include all transcript turns").option("--reverse", "Print newest transcript turns first").option("--json", "Print JSON output").option("--jsonl", "Print JSON Lines output").option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").action(async (sessionIdArg, options) => {
|
|
182767
|
+
const sessionHistoryCommand = new Command("history").description("Read visible session transcript history").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--limit <count>", "Maximum number of transcript turns to print", parsePositiveIntOption$1).option("--all", "Include all transcript turns").option("--reverse", "Print newest transcript turns first").option("--offline", "Read the local cache without syncing first").option("--json", "Print JSON output").option("--jsonl", "Print JSON Lines output").option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").action(async (sessionIdArg, options) => {
|
|
181929
182768
|
await runSessionCommand(options, async () => {
|
|
181930
182769
|
const outputMode = resolveStructuredOutputMode(options);
|
|
181931
182770
|
if (options.all && typeof options.limit === "number") {
|
|
@@ -181936,8 +182775,13 @@ ${entry.text}`).join("\n\n");
|
|
|
181936
182775
|
if (!sessionId) {
|
|
181937
182776
|
throw new Error("Missing session ID. Pass one explicitly or set LODY_SESSION_ID.");
|
|
181938
182777
|
}
|
|
181939
|
-
const workspace = await resolveWorkspaceForSessionOrThrow(auth, sessionId,
|
|
182778
|
+
const workspace = await resolveWorkspaceForSessionOrThrow(auth, sessionId, {
|
|
182779
|
+
workspace: options.workspace,
|
|
182780
|
+
offline: options.offline,
|
|
182781
|
+
reason: `session.history.resolve:${sessionId}`
|
|
182782
|
+
});
|
|
181940
182783
|
await withWorkspaceManager(auth, workspace, async (manager) => {
|
|
182784
|
+
await syncSessionReadData(manager, sessionId, options.offline, `session.history:${sessionId}`);
|
|
181941
182785
|
await resolveSessionMetaOrThrow(manager, sessionId);
|
|
181942
182786
|
const sessionDoc = await manager.getOrCreateSessionDoc(sessionId);
|
|
181943
182787
|
const transcript = toSessionTranscriptEntries(await sessionDoc.getHistory());
|
|
@@ -181971,15 +182815,20 @@ ${entry.text}`).join("\n\n");
|
|
|
181971
182815
|
});
|
|
181972
182816
|
});
|
|
181973
182817
|
});
|
|
181974
|
-
const sessionShowCommand = new Command("show").description("Show session metadata").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--json", "Print JSON output").option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").action(async (sessionIdArg, options) => {
|
|
182818
|
+
const sessionShowCommand = new Command("show").description("Show session metadata").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--offline", "Read the local cache without syncing first").option("--json", "Print JSON output").option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").action(async (sessionIdArg, options) => {
|
|
181975
182819
|
await runSessionCommand(options, async () => {
|
|
181976
182820
|
const auth = getAuthContextOrThrow();
|
|
181977
182821
|
const sessionId = normalizeCliValue(sessionIdArg) ?? normalizeCliValue(process.env.LODY_SESSION_ID);
|
|
181978
182822
|
if (!sessionId) {
|
|
181979
182823
|
throw new Error("Missing session ID. Pass one explicitly or set LODY_SESSION_ID.");
|
|
181980
182824
|
}
|
|
181981
|
-
const workspace = await resolveWorkspaceForSessionOrThrow(auth, sessionId,
|
|
182825
|
+
const workspace = await resolveWorkspaceForSessionOrThrow(auth, sessionId, {
|
|
182826
|
+
workspace: options.workspace,
|
|
182827
|
+
offline: options.offline,
|
|
182828
|
+
reason: `session.show.resolve:${sessionId}`
|
|
182829
|
+
});
|
|
181982
182830
|
await withWorkspaceManager(auth, workspace, async (manager) => {
|
|
182831
|
+
await syncSessionReadData(manager, sessionId, options.offline, `session.show:${sessionId}`);
|
|
181983
182832
|
const result = await buildSessionShowResult(workspace, manager, sessionId);
|
|
181984
182833
|
if (options.json) {
|
|
181985
182834
|
printJson({
|
|
@@ -181992,6 +182841,32 @@ ${entry.text}`).join("\n\n");
|
|
|
181992
182841
|
});
|
|
181993
182842
|
});
|
|
181994
182843
|
});
|
|
182844
|
+
const sessionStatusCommand = new Command("status").description("Show current session status").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--offline", "Read the local cache without syncing first").option("--json", "Print JSON output").option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").action(async (sessionIdArg, options) => {
|
|
182845
|
+
await runSessionCommand(options, async () => {
|
|
182846
|
+
const auth = getAuthContextOrThrow();
|
|
182847
|
+
const sessionId = normalizeCliValue(sessionIdArg) ?? normalizeCliValue(process.env.LODY_SESSION_ID);
|
|
182848
|
+
if (!sessionId) {
|
|
182849
|
+
throw new Error("Missing session ID. Pass one explicitly or set LODY_SESSION_ID.");
|
|
182850
|
+
}
|
|
182851
|
+
const workspace = await resolveWorkspaceForSessionOrThrow(auth, sessionId, {
|
|
182852
|
+
workspace: options.workspace,
|
|
182853
|
+
offline: options.offline,
|
|
182854
|
+
reason: `session.status.resolve:${sessionId}`
|
|
182855
|
+
});
|
|
182856
|
+
await withWorkspaceManager(auth, workspace, async (manager) => {
|
|
182857
|
+
await syncSessionReadData(manager, sessionId, options.offline, `session.status:${sessionId}`);
|
|
182858
|
+
const result = await buildSessionStatusResult(workspace, manager, sessionId);
|
|
182859
|
+
if (options.json) {
|
|
182860
|
+
printJson({
|
|
182861
|
+
ok: true,
|
|
182862
|
+
...result
|
|
182863
|
+
});
|
|
182864
|
+
return;
|
|
182865
|
+
}
|
|
182866
|
+
printHumanSessionStatus(result);
|
|
182867
|
+
});
|
|
182868
|
+
});
|
|
182869
|
+
});
|
|
181995
182870
|
const sessionRenameCommand = new Command("rename").description("Rename a session").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--title <title>", "New session title").option("--json", "Print JSON output").option("--debug", "Enable debug output").argument("[sessionId]", "Session ID; falls back to LODY_SESSION_ID").argument("[title]", "New session title").action(async (sessionIdArg, titleArg, options) => {
|
|
181996
182871
|
await runSessionCommand(options, async () => {
|
|
181997
182872
|
const auth = getAuthContextOrThrow();
|
|
@@ -182200,7 +183075,270 @@ ${entry.text}`).join("\n\n");
|
|
|
182200
183075
|
});
|
|
182201
183076
|
});
|
|
182202
183077
|
});
|
|
182203
|
-
const sessionCommand = new Command("session").description("Manage sessions without the web UI").addCommand(sessionCreateCommand).addCommand(sessionChatCommand).addCommand(sessionCancelCommand).addCommand(sessionListCommand).addCommand(sessionHistoryCommand).addCommand(sessionShowCommand).addCommand(sessionRenameCommand).addCommand(sessionArchiveCommand).addCommand(sessionRestoreCommand).addCommand(sessionDeleteCommand);
|
|
183078
|
+
const sessionCommand = new Command("session").description("Manage sessions without the web UI").addCommand(sessionCreateCommand).addCommand(sessionChatCommand).addCommand(sessionCancelCommand).addCommand(sessionListCommand).addCommand(sessionHistoryCommand).addCommand(sessionShowCommand).addCommand(sessionStatusCommand).addCommand(sessionRenameCommand).addCommand(sessionArchiveCommand).addCommand(sessionRestoreCommand).addCommand(sessionDeleteCommand);
|
|
183079
|
+
async function mapWithConcurrency(items2, concurrency, worker) {
|
|
183080
|
+
if (items2.length === 0) {
|
|
183081
|
+
return [];
|
|
183082
|
+
}
|
|
183083
|
+
const limit2 = Math.max(1, Math.floor(concurrency));
|
|
183084
|
+
const results = new Array(items2.length);
|
|
183085
|
+
let nextIndex = 0;
|
|
183086
|
+
const runWorker = async () => {
|
|
183087
|
+
while (nextIndex < items2.length) {
|
|
183088
|
+
const currentIndex = nextIndex;
|
|
183089
|
+
nextIndex += 1;
|
|
183090
|
+
results[currentIndex] = await worker(items2[currentIndex], currentIndex);
|
|
183091
|
+
}
|
|
183092
|
+
};
|
|
183093
|
+
await Promise.all(Array.from({
|
|
183094
|
+
length: Math.min(limit2, items2.length)
|
|
183095
|
+
}, () => runWorker()));
|
|
183096
|
+
return results;
|
|
183097
|
+
}
|
|
183098
|
+
const DEFAULT_SYNC_CONCURRENCY = 4;
|
|
183099
|
+
function parsePositiveIntOption(value) {
|
|
183100
|
+
const parsed = Number.parseInt(value, 10);
|
|
183101
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
183102
|
+
throw new Error(`Invalid numeric value: ${value}`);
|
|
183103
|
+
}
|
|
183104
|
+
return parsed;
|
|
183105
|
+
}
|
|
183106
|
+
function createWorkspaceSummary(workspaceId) {
|
|
183107
|
+
return {
|
|
183108
|
+
workspaceId,
|
|
183109
|
+
totals: {
|
|
183110
|
+
meta: 0,
|
|
183111
|
+
doc: 0,
|
|
183112
|
+
flock: 0
|
|
183113
|
+
},
|
|
183114
|
+
completed: {
|
|
183115
|
+
meta: 0,
|
|
183116
|
+
doc: 0,
|
|
183117
|
+
flock: 0
|
|
183118
|
+
},
|
|
183119
|
+
failed: {
|
|
183120
|
+
meta: 0,
|
|
183121
|
+
doc: 0,
|
|
183122
|
+
flock: 0
|
|
183123
|
+
},
|
|
183124
|
+
failures: []
|
|
183125
|
+
};
|
|
183126
|
+
}
|
|
183127
|
+
function mergeSummaries(workspaces) {
|
|
183128
|
+
const failures2 = workspaces.flatMap((workspace) => workspace.failures);
|
|
183129
|
+
let total = 0;
|
|
183130
|
+
let completed = 0;
|
|
183131
|
+
let failed = 0;
|
|
183132
|
+
for (const workspace of workspaces) {
|
|
183133
|
+
for (const kind of [
|
|
183134
|
+
"meta",
|
|
183135
|
+
"doc",
|
|
183136
|
+
"flock"
|
|
183137
|
+
]) {
|
|
183138
|
+
total += workspace.totals[kind];
|
|
183139
|
+
completed += workspace.completed[kind];
|
|
183140
|
+
failed += workspace.failed[kind];
|
|
183141
|
+
}
|
|
183142
|
+
}
|
|
183143
|
+
return {
|
|
183144
|
+
ok: failures2.length === 0,
|
|
183145
|
+
workspaces,
|
|
183146
|
+
total,
|
|
183147
|
+
completed,
|
|
183148
|
+
failed,
|
|
183149
|
+
failures: failures2
|
|
183150
|
+
};
|
|
183151
|
+
}
|
|
183152
|
+
function buildProgressEvent(input2) {
|
|
183153
|
+
return {
|
|
183154
|
+
type: "progress",
|
|
183155
|
+
workspaceId: input2.workspaceId,
|
|
183156
|
+
kind: input2.kind,
|
|
183157
|
+
id: input2.id,
|
|
183158
|
+
total: input2.total,
|
|
183159
|
+
completed: input2.completed,
|
|
183160
|
+
failed: input2.failed,
|
|
183161
|
+
remaining: Math.max(0, input2.total - input2.completed - input2.failed),
|
|
183162
|
+
ok: input2.ok,
|
|
183163
|
+
...input2.error ? {
|
|
183164
|
+
error: input2.error
|
|
183165
|
+
} : {}
|
|
183166
|
+
};
|
|
183167
|
+
}
|
|
183168
|
+
function printHumanProgress(event) {
|
|
183169
|
+
const status = event.ok ? "synced" : "failed";
|
|
183170
|
+
const failedText = event.failed > 0 ? `, failed ${event.failed}` : "";
|
|
183171
|
+
console.log(`[${event.workspaceId}] ${event.kind} ${event.id}: ${status} (${event.completed}/${event.total}${failedText})`);
|
|
183172
|
+
if (event.error) {
|
|
183173
|
+
console.log(` ${event.error}`);
|
|
183174
|
+
}
|
|
183175
|
+
}
|
|
183176
|
+
function emitProgress(event, outputMode) {
|
|
183177
|
+
if (outputMode === "jsonl") {
|
|
183178
|
+
printJson(event);
|
|
183179
|
+
return;
|
|
183180
|
+
}
|
|
183181
|
+
if (outputMode === "human") {
|
|
183182
|
+
printHumanProgress(event);
|
|
183183
|
+
}
|
|
183184
|
+
}
|
|
183185
|
+
function recordSyncResult(args2) {
|
|
183186
|
+
if (args2.ok) {
|
|
183187
|
+
args2.summary.completed[args2.kind] += 1;
|
|
183188
|
+
} else {
|
|
183189
|
+
args2.summary.failed[args2.kind] += 1;
|
|
183190
|
+
args2.summary.failures.push({
|
|
183191
|
+
workspaceId: args2.summary.workspaceId,
|
|
183192
|
+
kind: args2.kind,
|
|
183193
|
+
id: args2.id,
|
|
183194
|
+
error: args2.error ?? "Sync failed."
|
|
183195
|
+
});
|
|
183196
|
+
}
|
|
183197
|
+
emitProgress(buildProgressEvent({
|
|
183198
|
+
workspaceId: args2.summary.workspaceId,
|
|
183199
|
+
kind: args2.kind,
|
|
183200
|
+
id: args2.id,
|
|
183201
|
+
total: args2.summary.totals[args2.kind],
|
|
183202
|
+
completed: args2.summary.completed[args2.kind],
|
|
183203
|
+
failed: args2.summary.failed[args2.kind],
|
|
183204
|
+
ok: args2.ok,
|
|
183205
|
+
error: args2.error
|
|
183206
|
+
}), args2.outputMode);
|
|
183207
|
+
}
|
|
183208
|
+
async function syncItems(input2) {
|
|
183209
|
+
input2.summary.totals[input2.kind] = input2.ids.length;
|
|
183210
|
+
await mapWithConcurrency(input2.ids, input2.concurrency, async (id2) => {
|
|
183211
|
+
try {
|
|
183212
|
+
await input2.syncOne(id2);
|
|
183213
|
+
recordSyncResult({
|
|
183214
|
+
summary: input2.summary,
|
|
183215
|
+
kind: input2.kind,
|
|
183216
|
+
id: id2,
|
|
183217
|
+
ok: true,
|
|
183218
|
+
outputMode: input2.outputMode
|
|
183219
|
+
});
|
|
183220
|
+
} catch (error2) {
|
|
183221
|
+
recordSyncResult({
|
|
183222
|
+
summary: input2.summary,
|
|
183223
|
+
kind: input2.kind,
|
|
183224
|
+
id: id2,
|
|
183225
|
+
ok: false,
|
|
183226
|
+
error: formatErrorMessage(error2),
|
|
183227
|
+
outputMode: input2.outputMode
|
|
183228
|
+
});
|
|
183229
|
+
}
|
|
183230
|
+
});
|
|
183231
|
+
}
|
|
183232
|
+
async function listMachineFlockDocIds(manager, workspaceId) {
|
|
183233
|
+
const machines = await listAliveDocMetas(manager, isMachineDocRoomId);
|
|
183234
|
+
return machines.map((entry) => getMachineFlockDocId(workspaceId, entry.meta.id)).sort((left2, right2) => left2.localeCompare(right2));
|
|
183235
|
+
}
|
|
183236
|
+
async function syncWorkspace(input2) {
|
|
183237
|
+
const workspaceId = input2.workspace.id;
|
|
183238
|
+
const summary2 = createWorkspaceSummary(input2.workspace.id);
|
|
183239
|
+
await withWorkspaceManager$1(input2.auth, input2.workspace, "sync", async (manager) => {
|
|
183240
|
+
summary2.totals.meta = 1;
|
|
183241
|
+
try {
|
|
183242
|
+
await manager.syncMetaOrThrow({
|
|
183243
|
+
reason: `sync:${workspaceId}:meta`
|
|
183244
|
+
});
|
|
183245
|
+
recordSyncResult({
|
|
183246
|
+
summary: summary2,
|
|
183247
|
+
kind: "meta",
|
|
183248
|
+
id: "meta",
|
|
183249
|
+
ok: true,
|
|
183250
|
+
outputMode: input2.outputMode
|
|
183251
|
+
});
|
|
183252
|
+
} catch (error2) {
|
|
183253
|
+
recordSyncResult({
|
|
183254
|
+
summary: summary2,
|
|
183255
|
+
kind: "meta",
|
|
183256
|
+
id: "meta",
|
|
183257
|
+
ok: false,
|
|
183258
|
+
error: formatErrorMessage(error2),
|
|
183259
|
+
outputMode: input2.outputMode
|
|
183260
|
+
});
|
|
183261
|
+
return;
|
|
183262
|
+
}
|
|
183263
|
+
const docIds = (await listAliveRoomIds(manager, () => true)).sort((left2, right2) => left2.localeCompare(right2));
|
|
183264
|
+
const flockDocIds = await listMachineFlockDocIds(manager, workspaceId);
|
|
183265
|
+
await syncItems({
|
|
183266
|
+
summary: summary2,
|
|
183267
|
+
kind: "doc",
|
|
183268
|
+
ids: docIds,
|
|
183269
|
+
concurrency: input2.concurrency,
|
|
183270
|
+
outputMode: input2.outputMode,
|
|
183271
|
+
syncOne: async (id2) => {
|
|
183272
|
+
await manager.syncDocOrThrow(id2, {
|
|
183273
|
+
reason: `sync:${workspaceId}:doc:${id2}`
|
|
183274
|
+
});
|
|
183275
|
+
}
|
|
183276
|
+
});
|
|
183277
|
+
await syncItems({
|
|
183278
|
+
summary: summary2,
|
|
183279
|
+
kind: "flock",
|
|
183280
|
+
ids: flockDocIds,
|
|
183281
|
+
concurrency: input2.concurrency,
|
|
183282
|
+
outputMode: input2.outputMode,
|
|
183283
|
+
syncOne: async (id2) => {
|
|
183284
|
+
await manager.syncFlockDocOrThrow(id2, {
|
|
183285
|
+
reason: `sync:${workspaceId}:flock:${id2}`
|
|
183286
|
+
});
|
|
183287
|
+
}
|
|
183288
|
+
});
|
|
183289
|
+
});
|
|
183290
|
+
return summary2;
|
|
183291
|
+
}
|
|
183292
|
+
function printHumanSummary(summary2) {
|
|
183293
|
+
console.log(`Finished sync: ${summary2.completed}/${summary2.total} item(s) synced, ${summary2.failed} failed.`);
|
|
183294
|
+
if (summary2.failures.length > 0) {
|
|
183295
|
+
console.log("Failures:");
|
|
183296
|
+
for (const failure of summary2.failures) {
|
|
183297
|
+
console.log(`- [${failure.workspaceId}] ${failure.kind} ${failure.id}: ${failure.error}`);
|
|
183298
|
+
}
|
|
183299
|
+
}
|
|
183300
|
+
}
|
|
183301
|
+
function createAlreadyPrintedError() {
|
|
183302
|
+
return Object.assign(new Error("Sync completed with failures."), {
|
|
183303
|
+
suppressCommandErrorOutput: true,
|
|
183304
|
+
exitCode: 1
|
|
183305
|
+
});
|
|
183306
|
+
}
|
|
183307
|
+
const syncCommand = new Command("sync").description("Sync workspace Loro data to the local cache").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--all-workspace", "Sync all accessible workspaces").option("--concurrency <count>", "Maximum number of documents to sync concurrently", parsePositiveIntOption, DEFAULT_SYNC_CONCURRENCY).option("--json", "Print final JSON summary").option("--jsonl", "Print JSON Lines progress events and final summary").option("--debug", "Enable debug output").action(async (options) => {
|
|
183308
|
+
await runOneShotCommand("sync", options, async () => {
|
|
183309
|
+
const outputMode = resolveStructuredOutputMode$1(options);
|
|
183310
|
+
const auth = getAuthContextOrThrow$1("sync");
|
|
183311
|
+
if (options.allWorkspace && options.workspace) {
|
|
183312
|
+
throw new Error("Pass either --workspace or --all-workspace, not both.");
|
|
183313
|
+
}
|
|
183314
|
+
const workspaces = options.allWorkspace ? await listWorkspacesForToken(auth.token) : [
|
|
183315
|
+
await resolveWorkspaceOrThrow$1(auth, options.workspace)
|
|
183316
|
+
];
|
|
183317
|
+
const workspaceSummaries = [];
|
|
183318
|
+
for (const workspace of workspaces) {
|
|
183319
|
+
workspaceSummaries.push(await syncWorkspace({
|
|
183320
|
+
auth,
|
|
183321
|
+
workspace,
|
|
183322
|
+
concurrency: options.concurrency ?? DEFAULT_SYNC_CONCURRENCY,
|
|
183323
|
+
outputMode
|
|
183324
|
+
}));
|
|
183325
|
+
}
|
|
183326
|
+
const summary2 = mergeSummaries(workspaceSummaries);
|
|
183327
|
+
if (outputMode === "jsonl") {
|
|
183328
|
+
printJson({
|
|
183329
|
+
type: "summary",
|
|
183330
|
+
...summary2
|
|
183331
|
+
});
|
|
183332
|
+
} else if (outputMode === "json") {
|
|
183333
|
+
printJson(summary2);
|
|
183334
|
+
} else {
|
|
183335
|
+
printHumanSummary(summary2);
|
|
183336
|
+
}
|
|
183337
|
+
if (!summary2.ok) {
|
|
183338
|
+
throw createAlreadyPrintedError();
|
|
183339
|
+
}
|
|
183340
|
+
});
|
|
183341
|
+
});
|
|
182204
183342
|
function sortWorkspaceSummaries(workspaces) {
|
|
182205
183343
|
return [
|
|
182206
183344
|
...workspaces
|
|
@@ -182342,19 +183480,53 @@ ${entry.text}`).join("\n\n");
|
|
|
182342
183480
|
} : {}
|
|
182343
183481
|
};
|
|
182344
183482
|
}
|
|
182345
|
-
function toMachineJsonEntry(machine,
|
|
182346
|
-
|
|
182347
|
-
|
|
183483
|
+
function toMachineJsonEntry(machine, options) {
|
|
183484
|
+
const withoutOptional = {
|
|
183485
|
+
...machine
|
|
183486
|
+
};
|
|
183487
|
+
if (!options.includeAcpCapabilities) {
|
|
183488
|
+
delete withoutOptional.acpCapabilities;
|
|
182348
183489
|
}
|
|
182349
|
-
|
|
182350
|
-
|
|
183490
|
+
if (!options.includeAgents) {
|
|
183491
|
+
delete withoutOptional.agentConfigs;
|
|
183492
|
+
}
|
|
183493
|
+
return withoutOptional;
|
|
183494
|
+
}
|
|
183495
|
+
function formatMachineAgents(machine) {
|
|
183496
|
+
const configs = machine.agentConfigs ?? [];
|
|
183497
|
+
if (configs.length === 0) {
|
|
183498
|
+
return "-";
|
|
183499
|
+
}
|
|
183500
|
+
return configs.map((config2) => `${config2.name} (${config2.agentType})`).join(",");
|
|
182351
183501
|
}
|
|
182352
|
-
function
|
|
183502
|
+
async function attachAgentConfigsToMachines(repo, workspaceId, machines) {
|
|
183503
|
+
const configs = await listMergedAgentConfigs(repo, workspaceId, machines.map((machine) => machine.id));
|
|
183504
|
+
const configsByMachine = /* @__PURE__ */ new Map();
|
|
183505
|
+
for (const config2 of configs) {
|
|
183506
|
+
const current2 = configsByMachine.get(config2.machineId) ?? [];
|
|
183507
|
+
current2.push(config2);
|
|
183508
|
+
configsByMachine.set(config2.machineId, current2);
|
|
183509
|
+
}
|
|
183510
|
+
for (const values of configsByMachine.values()) {
|
|
183511
|
+
values.sort((left2, right2) => {
|
|
183512
|
+
const nameCompare = left2.name.localeCompare(right2.name);
|
|
183513
|
+
if (nameCompare !== 0) {
|
|
183514
|
+
return nameCompare;
|
|
183515
|
+
}
|
|
183516
|
+
return left2.id.localeCompare(right2.id);
|
|
183517
|
+
});
|
|
183518
|
+
}
|
|
183519
|
+
return machines.map((machine) => ({
|
|
183520
|
+
...machine,
|
|
183521
|
+
agentConfigs: configsByMachine.get(machine.id) ?? []
|
|
183522
|
+
}));
|
|
183523
|
+
}
|
|
183524
|
+
function printHumanMachineList(machines, currentMachineId, includeAgents) {
|
|
182353
183525
|
if (machines.length === 0) {
|
|
182354
183526
|
console.log("No machines found.");
|
|
182355
183527
|
return;
|
|
182356
183528
|
}
|
|
182357
|
-
|
|
183529
|
+
const columns = [
|
|
182358
183530
|
{
|
|
182359
183531
|
header: "ID"
|
|
182360
183532
|
},
|
|
@@ -182367,30 +183539,49 @@ ${entry.text}`).join("\n\n");
|
|
|
182367
183539
|
{
|
|
182368
183540
|
header: "CLI"
|
|
182369
183541
|
}
|
|
182370
|
-
]
|
|
182371
|
-
|
|
182372
|
-
|
|
182373
|
-
|
|
182374
|
-
|
|
182375
|
-
|
|
183542
|
+
];
|
|
183543
|
+
if (includeAgents) {
|
|
183544
|
+
columns.push({
|
|
183545
|
+
header: "Agents"
|
|
183546
|
+
});
|
|
183547
|
+
}
|
|
183548
|
+
console.log(renderTerminalTable(columns, machines.map((machine) => {
|
|
183549
|
+
const row = [
|
|
183550
|
+
machine.id,
|
|
183551
|
+
machine.id === currentMachineId ? `${machine.name} (current)` : machine.name,
|
|
183552
|
+
machine.online ? "online" : "offline",
|
|
183553
|
+
formatMachineCli(machine)
|
|
183554
|
+
];
|
|
183555
|
+
if (includeAgents) {
|
|
183556
|
+
row.push(formatMachineAgents(machine));
|
|
183557
|
+
}
|
|
183558
|
+
return row;
|
|
183559
|
+
})));
|
|
182376
183560
|
}
|
|
182377
|
-
const machineCommand = new Command("machine").description("Inspect registered machines").addCommand(new Command("list").description("List machines in a workspace").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--online-only", "Only include machines with a recent heartbeat").option("--json", "Print JSON output").option("--include-acp-capabilities", "Include acpCapabilities in JSON output").option("--debug", "Enable debug output").action(async (options) => {
|
|
183561
|
+
const machineCommand = new Command("machine").description("Inspect registered machines").addCommand(new Command("list").description("List machines in a workspace").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--online-only", "Only include machines with a recent heartbeat").option("--json", "Print JSON output").option("--include-acp-capabilities", "Include acpCapabilities in JSON output").option("--include-agents", "Include agent config summaries per machine").option("--debug", "Enable debug output").action(async (options) => {
|
|
182378
183562
|
await runOneShotCommand("machine", options, async () => {
|
|
182379
183563
|
const auth = getAuthContextOrThrow$1("machine");
|
|
182380
183564
|
const workspace = await resolveWorkspaceOrThrow$1(auth, options.workspace);
|
|
182381
183565
|
await withWorkspaceManager$1(auth, workspace, "machine", async (manager) => {
|
|
182382
|
-
|
|
183566
|
+
let machines = sortMachineMetas((await listAliveDocMetas(manager, isMachineDocRoomId)).map((entry) => entry.meta), auth.machineId).map(toMachineListEntry).filter((machine) => !options.onlineOnly || machine.online);
|
|
183567
|
+
if (options.includeAgents === true) {
|
|
183568
|
+
machines = await attachAgentConfigsToMachines(manager.repo, workspace.id, machines);
|
|
183569
|
+
}
|
|
182383
183570
|
if (options.json) {
|
|
182384
183571
|
const includeAcpCapabilities = options.includeAcpCapabilities === true;
|
|
183572
|
+
const includeAgents = options.includeAgents === true;
|
|
182385
183573
|
const jsonMachines = await Promise.all(machines.map((machine) => mergeMachineFlockJsonState(manager.repo, workspace.id, machine, includeAcpCapabilities)));
|
|
182386
183574
|
printJson({
|
|
182387
183575
|
ok: true,
|
|
182388
183576
|
workspaceId: workspace.id,
|
|
182389
|
-
machines: jsonMachines.map((machine) => toMachineJsonEntry(machine,
|
|
183577
|
+
machines: jsonMachines.map((machine) => toMachineJsonEntry(machine, {
|
|
183578
|
+
includeAcpCapabilities,
|
|
183579
|
+
includeAgents
|
|
183580
|
+
}))
|
|
182390
183581
|
});
|
|
182391
183582
|
return;
|
|
182392
183583
|
}
|
|
182393
|
-
printHumanMachineList(machines, auth.machineId);
|
|
183584
|
+
printHumanMachineList(machines, auth.machineId, options.includeAgents === true);
|
|
182394
183585
|
});
|
|
182395
183586
|
});
|
|
182396
183587
|
}));
|
|
@@ -182572,25 +183763,6 @@ ${entry.text}`).join("\n\n");
|
|
|
182572
183763
|
].sort((left2, right2) => left2.imageId.localeCompare(right2.imageId))
|
|
182573
183764
|
};
|
|
182574
183765
|
}
|
|
182575
|
-
async function mapWithConcurrency(items2, concurrency, worker) {
|
|
182576
|
-
if (items2.length === 0) {
|
|
182577
|
-
return [];
|
|
182578
|
-
}
|
|
182579
|
-
const limit2 = Math.max(1, Math.floor(concurrency));
|
|
182580
|
-
const results = new Array(items2.length);
|
|
182581
|
-
let nextIndex = 0;
|
|
182582
|
-
const runWorker = async () => {
|
|
182583
|
-
while (nextIndex < items2.length) {
|
|
182584
|
-
const currentIndex = nextIndex;
|
|
182585
|
-
nextIndex += 1;
|
|
182586
|
-
results[currentIndex] = await worker(items2[currentIndex], currentIndex);
|
|
182587
|
-
}
|
|
182588
|
-
};
|
|
182589
|
-
await Promise.all(Array.from({
|
|
182590
|
-
length: Math.min(limit2, items2.length)
|
|
182591
|
-
}, () => runWorker()));
|
|
182592
|
-
return results;
|
|
182593
|
-
}
|
|
182594
183766
|
const MIME_EXTENSION_MAP = {
|
|
182595
183767
|
"image/png": ".png",
|
|
182596
183768
|
"image/jpeg": ".jpg",
|
|
@@ -183011,6 +184183,7 @@ ${entry.text}`).join("\n\n");
|
|
|
183011
184183
|
warnings
|
|
183012
184184
|
};
|
|
183013
184185
|
}
|
|
184186
|
+
const EXPORT_SYNC_CONCURRENCY = 4;
|
|
183014
184187
|
function buildDefaultOutputDir() {
|
|
183015
184188
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
|
|
183016
184189
|
return path__default$1.resolve(process.cwd(), `lody-export-${timestamp2}`);
|
|
@@ -183019,7 +184192,14 @@ ${entry.text}`).join("\n\n");
|
|
|
183019
184192
|
const candidate = (workspace.slug?.trim() || workspace.id).trim();
|
|
183020
184193
|
return candidate.replace(/[\\/]/g, "_");
|
|
183021
184194
|
}
|
|
183022
|
-
|
|
184195
|
+
async function syncWorkspaceSessionsForExport(manager, workspace) {
|
|
184196
|
+
await syncWorkspaceMetaForRead(manager, `export:${workspace.id}:meta`);
|
|
184197
|
+
const sessions = await listAliveDocMetas(manager, isSessionDocRoomId);
|
|
184198
|
+
await mapWithConcurrency(sessions, EXPORT_SYNC_CONCURRENCY, async (entry) => {
|
|
184199
|
+
await syncDocForRead(manager, getSessionRoomId(entry.meta.id), `export:${workspace.id}:${entry.meta.id}`);
|
|
184200
|
+
});
|
|
184201
|
+
}
|
|
184202
|
+
const exportCommand = new Command("export").description("Export user-facing workspace session data").option("--workspace <idOrSlug>", "Target workspace id or slug").option("--all-workspace", "Export all accessible workspaces").option("--no-images", "Skip downloading image binaries").option("--offline", "Read the local cache without syncing first").option("--debug", "Enable debug output").argument("[outputDir]", "Output directory for export files").action(async (outputDirArg, options) => {
|
|
183023
184203
|
await runOneShotCommand("export", options, async () => {
|
|
183024
184204
|
const auth = getAuthContextOrThrow$1("export");
|
|
183025
184205
|
const outputDir = path__default$1.resolve(outputDirArg ?? buildDefaultOutputDir());
|
|
@@ -183034,6 +184214,9 @@ ${entry.text}`).join("\n\n");
|
|
|
183034
184214
|
for (const workspace of workspaces) {
|
|
183035
184215
|
const workspaceOutputDir = path__default$1.join(outputDir, toWorkspaceDirName(workspace));
|
|
183036
184216
|
const result = await withWorkspaceManager$1(auth, workspace, "export", async (manager) => {
|
|
184217
|
+
if (options.offline !== true) {
|
|
184218
|
+
await syncWorkspaceSessionsForExport(manager, workspace);
|
|
184219
|
+
}
|
|
183037
184220
|
return await exportWorkspaceData({
|
|
183038
184221
|
manager,
|
|
183039
184222
|
workspace,
|
|
@@ -183157,7 +184340,7 @@ ${entry.text}`).join("\n\n");
|
|
|
183157
184340
|
data = createReviewBundleSnapshot(bundle);
|
|
183158
184341
|
}
|
|
183159
184342
|
const { injectReviewSnapshot } = await import("./chunks/index-VoI6Ds2-.js");
|
|
183160
|
-
const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer
|
|
184343
|
+
const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer--K5LcsS4.js");
|
|
183161
184344
|
const template = await resolveReviewViewerTemplate();
|
|
183162
184345
|
const html = injectReviewSnapshot(template, data);
|
|
183163
184346
|
const outputPath = options.output ? path__default$1.resolve(options.output) : defaultHtmlOutputPath(inputPath);
|
|
@@ -200486,6 +201669,7 @@ ${lines2.join("\n")}` : ""}${suffix}`);
|
|
|
200486
201669
|
program.addCommand(startCommand);
|
|
200487
201670
|
program.addCommand(projectCommand);
|
|
200488
201671
|
program.addCommand(sessionCommand);
|
|
201672
|
+
program.addCommand(syncCommand);
|
|
200489
201673
|
program.addCommand(workspaceCommand);
|
|
200490
201674
|
program.addCommand(agentConfigCommand);
|
|
200491
201675
|
program.addCommand(machineCommand);
|