lody 0.65.0 → 0.66.1

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.
@@ -3,7 +3,7 @@ import { readFile, mkdir, writeFile, rename } from "node:fs/promises";
3
3
  import os__default from "node:os";
4
4
  import path__default from "node:path";
5
5
  import process from "node:process";
6
- const reviewViewerVersion = "0.65.0";
6
+ const reviewViewerVersion = "0.66.1";
7
7
  const reviewViewerSha256 = "50ab599b652bdf4b959b539ea948454dd588703039bd4c5c037c7877ce10696f";
8
8
  const reviewViewerFileName = "standalone.html";
9
9
  const DEFAULT_CDN_BASES = ["https://cdn.jsdelivr.net/npm", "https://unpkg.com"];
package/dist/index.js CHANGED
@@ -36839,7 +36839,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
36839
36839
  return client;
36840
36840
  }
36841
36841
  const name$1 = "lody";
36842
- const version$3 = "0.65.0";
36842
+ const version$3 = "0.66.1";
36843
36843
  const description$1 = "Lody Agent CLI tool for managing remote command execution";
36844
36844
  const type$2 = "module";
36845
36845
  const main$4 = "dist/index.js";
@@ -36849,7 +36849,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
36849
36849
  const scripts = {
36850
36850
  "dev": "node dev.mjs",
36851
36851
  "dev:staging": "LODY_AUTH_URL=https://impressive-guineapig-165.convex.cloud LODY_AUTH_SITE_URL=https://impressive-guineapig-165.convex.site LODY_SERVER_URL=https://lody-server.zx-073.workers.dev SITE_URL=https://main.lody.pages.dev/ pnpm run dev",
36852
- "dev:prod": "LODY_AUTH_URL=https://nautical-curlew-181.convex.cloud LODY_SERVER_URL=https://api.lody.ai pnpm run dev",
36852
+ "dev:prod": "LODY_AUTH_URL=https://convex.lody.ai LODY_SERVER_URL=https://api.lody.ai pnpm run dev",
36853
36853
  "build": "pnpm run clean && pnpm run typecheck && pnpm run build:bundle && pnpm run check:published-bundle-imports && pnpm run copy:wasm",
36854
36854
  "build:watch": "pnpm run prepare:review-assets && vite build --watch",
36855
36855
  "build:bundle": "pnpm run prepare:review-assets && vite build",
@@ -36884,7 +36884,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
36884
36884
  "node": ">=18.0.0"
36885
36885
  };
36886
36886
  const optionalDependencies = {
36887
- "acp-extension-claude": "0.50.0",
36887
+ "acp-extension-claude": "0.54.1",
36888
36888
  "acp-extension-codex": "0.15.0"
36889
36889
  };
36890
36890
  const devDependencies = {
@@ -42112,8 +42112,8 @@ Task description:
42112
42112
  const historyItemAnySchema = schema.Any({
42113
42113
  defaultLoroText: true
42114
42114
  });
42115
- const isRecord$9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
42116
- const isWorktreeScriptHistoryStep = (value) => isRecord$9(value) && typeof value.command === "string" && (value.status === "in_progress" || value.status === "completed" || value.status === "failed") && typeof value.output === "string";
42115
+ const isRecord$a = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
42116
+ const isWorktreeScriptHistoryStep = (value) => isRecord$a(value) && typeof value.command === "string" && (value.status === "in_progress" || value.status === "completed" || value.status === "failed") && typeof value.output === "string";
42117
42117
  const historyMessageItemSchema = schema.LoroMap({
42118
42118
  type: schema.String(),
42119
42119
  text: schema.LoroText({
@@ -44276,7 +44276,7 @@ Task description:
44276
44276
  "claude",
44277
44277
  "codex"
44278
44278
  ]);
44279
- function isRecord$8(value) {
44279
+ function isRecord$9(value) {
44280
44280
  return typeof value === "object" && value !== null;
44281
44281
  }
44282
44282
  function getTrimmedString(value) {
@@ -44293,7 +44293,7 @@ Task description:
44293
44293
  return value === "builtin" || value === "registry" || value === "custom";
44294
44294
  }
44295
44295
  function normalizeLegacyProjectRef(value) {
44296
- if (!isRecord$8(value)) {
44296
+ if (!isRecord$9(value)) {
44297
44297
  return value;
44298
44298
  }
44299
44299
  const kind = value.kind;
@@ -44309,13 +44309,13 @@ Task description:
44309
44309
  normalized.branch = existingBranch;
44310
44310
  } else {
44311
44311
  const legacyBranchFromString = getTrimmedString(legacyProject);
44312
- const legacyBranchFromObject = isRecord$8(legacyProject) ? getTrimmedString(legacyProject.branch) ?? getTrimmedString(legacyProject.project) : void 0;
44312
+ const legacyBranchFromObject = isRecord$9(legacyProject) ? getTrimmedString(legacyProject.branch) ?? getTrimmedString(legacyProject.project) : void 0;
44313
44313
  const resolvedBranch = legacyBranchFromString ?? legacyBranchFromObject;
44314
44314
  if (resolvedBranch) {
44315
44315
  normalized.branch = resolvedBranch;
44316
44316
  }
44317
44317
  }
44318
- if (isRecord$8(legacyProject)) {
44318
+ if (isRecord$9(legacyProject)) {
44319
44319
  if (kind === "github" && !getTrimmedString(normalized.repoFullName)) {
44320
44320
  const repoFullName = getTrimmedString(legacyProject.repoFullName);
44321
44321
  if (repoFullName) {
@@ -44352,7 +44352,7 @@ Task description:
44352
44352
  };
44353
44353
  normalized.project = normalizeLegacyProjectRef(normalized.project);
44354
44354
  const currentProject = normalized.project;
44355
- const projectRecord = isRecord$8(currentProject) ? currentProject : void 0;
44355
+ const projectRecord = isRecord$9(currentProject) ? currentProject : void 0;
44356
44356
  const explicitBranch = getTrimmedString(normalized.branch) ?? getTrimmedString(currentProject) ?? (projectRecord ? getTrimmedString(projectRecord.branch) ?? getTrimmedString(projectRecord.project) : void 0);
44357
44357
  const repoFullName = (projectRecord ? getTrimmedString(projectRecord.repoFullName) : void 0) ?? getTrimmedString(normalized.repoFullName) ?? getTrimmedString(normalized.githubRepo);
44358
44358
  const localProjectId = (projectRecord ? getTrimmedString(projectRecord.localProjectId) : void 0) ?? getTrimmedString(normalized.localProjectId);
@@ -44395,7 +44395,7 @@ Task description:
44395
44395
  return normalized;
44396
44396
  }
44397
44397
  function normalizeLegacyAcpSessionConfig(value) {
44398
- if (!isRecord$8(value)) {
44398
+ if (!isRecord$9(value)) {
44399
44399
  return value;
44400
44400
  }
44401
44401
  const normalized = {
@@ -44430,13 +44430,13 @@ Task description:
44430
44430
  return normalized;
44431
44431
  }
44432
44432
  function normalizeLegacySessionMessage(parsed) {
44433
- if (!isRecord$8(parsed)) {
44433
+ if (!isRecord$9(parsed)) {
44434
44434
  return parsed;
44435
44435
  }
44436
44436
  const messageType = parsed.type;
44437
44437
  if (messageType === "session/create" || messageType === "session/chat") {
44438
44438
  const normalized = normalizeLegacySessionProject(parsed);
44439
- if (!isRecord$8(normalized)) {
44439
+ if (!isRecord$9(normalized)) {
44440
44440
  return normalized;
44441
44441
  }
44442
44442
  normalized.acpSessionConfig = normalizeLegacyAcpSessionConfig(normalized.acpSessionConfig);
@@ -48632,17 +48632,17 @@ Task description:
48632
48632
  droppedNotifications
48633
48633
  };
48634
48634
  }
48635
- const isRecord$7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
48635
+ const isRecord$8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
48636
48636
  const getBooleanField = (value, camelCaseKey, snakeCaseKey) => value[camelCaseKey] === true || value[snakeCaseKey] === true;
48637
48637
  const getClaudeCodeMeta = (meta) => {
48638
- if (!isRecord$7(meta)) return null;
48638
+ if (!isRecord$8(meta)) return null;
48639
48639
  const claudeCode = meta.claudeCode;
48640
- return isRecord$7(claudeCode) ? claudeCode : null;
48640
+ return isRecord$8(claudeCode) ? claudeCode : null;
48641
48641
  };
48642
48642
  const getCodexMeta = (meta) => {
48643
- if (!isRecord$7(meta)) return null;
48643
+ if (!isRecord$8(meta)) return null;
48644
48644
  const codex = meta.codex;
48645
- return isRecord$7(codex) ? codex : null;
48645
+ return isRecord$8(codex) ? codex : null;
48646
48646
  };
48647
48647
  function parseAskUserQuestionPermissionMeta(meta) {
48648
48648
  const claudeCode = getClaudeCodeMeta(meta);
@@ -48657,18 +48657,18 @@ Task description:
48657
48657
  }
48658
48658
  function parseClaudeAskUserQuestionPermissionMeta(claudeCode) {
48659
48659
  const raw2 = claudeCode.askUserQuestion;
48660
- if (!isRecord$7(raw2)) return null;
48660
+ if (!isRecord$8(raw2)) return null;
48661
48661
  const rawQuestions = raw2.questions;
48662
48662
  if (!Array.isArray(rawQuestions) || rawQuestions.length === 0) return null;
48663
48663
  const questions = [];
48664
48664
  for (const rawQuestion of rawQuestions) {
48665
- if (!isRecord$7(rawQuestion)) return null;
48665
+ if (!isRecord$8(rawQuestion)) return null;
48666
48666
  if (typeof rawQuestion.question !== "string") return null;
48667
48667
  if (typeof rawQuestion.header !== "string") return null;
48668
48668
  if (!Array.isArray(rawQuestion.options)) return null;
48669
48669
  const options = [];
48670
48670
  for (const rawOption of rawQuestion.options) {
48671
- if (!isRecord$7(rawOption)) return null;
48671
+ if (!isRecord$8(rawOption)) return null;
48672
48672
  if (typeof rawOption.label !== "string") return null;
48673
48673
  options.push({
48674
48674
  label: rawOption.label,
@@ -48696,12 +48696,12 @@ Task description:
48696
48696
  }
48697
48697
  function parseCodexRequestUserInputPermissionMeta(codex) {
48698
48698
  const raw2 = codex.requestUserInput;
48699
- if (!isRecord$7(raw2)) return null;
48699
+ if (!isRecord$8(raw2)) return null;
48700
48700
  const rawQuestions = raw2.questions;
48701
48701
  if (!Array.isArray(rawQuestions) || rawQuestions.length === 0) return null;
48702
48702
  const questions = [];
48703
48703
  for (const rawQuestion of rawQuestions) {
48704
- if (!isRecord$7(rawQuestion)) return null;
48704
+ if (!isRecord$8(rawQuestion)) return null;
48705
48705
  if (typeof rawQuestion.id !== "string") return null;
48706
48706
  if (typeof rawQuestion.question !== "string") return null;
48707
48707
  if (typeof rawQuestion.header !== "string") return null;
@@ -48710,7 +48710,7 @@ Task description:
48710
48710
  if (rawOptions !== void 0) {
48711
48711
  if (!Array.isArray(rawOptions)) return null;
48712
48712
  for (const rawOption of rawOptions) {
48713
- if (!isRecord$7(rawOption)) return null;
48713
+ if (!isRecord$8(rawOption)) return null;
48714
48714
  if (typeof rawOption.label !== "string") return null;
48715
48715
  options.push({
48716
48716
  label: rawOption.label,
@@ -48772,16 +48772,16 @@ Task description:
48772
48772
  }
48773
48773
  const getCodexOutcomeAnswers = (outcomeMeta) => {
48774
48774
  const codex = getCodexMeta(outcomeMeta);
48775
- const requestUserInput = codex && isRecord$7(codex.requestUserInput) ? codex.requestUserInput : null;
48776
- return requestUserInput && isRecord$7(requestUserInput.answers) ? requestUserInput.answers : null;
48775
+ const requestUserInput = codex && isRecord$8(codex.requestUserInput) ? codex.requestUserInput : null;
48776
+ return requestUserInput && isRecord$8(requestUserInput.answers) ? requestUserInput.answers : null;
48777
48777
  };
48778
48778
  const getClaudeOutcomeAnswers = (outcomeMeta) => {
48779
48779
  const claudeCode = getClaudeCodeMeta(outcomeMeta);
48780
- const askUserQuestion = claudeCode && isRecord$7(claudeCode.askUserQuestion) ? claudeCode.askUserQuestion : null;
48781
- return askUserQuestion && isRecord$7(askUserQuestion.answers) ? askUserQuestion.answers : null;
48780
+ const askUserQuestion = claudeCode && isRecord$8(claudeCode.askUserQuestion) ? claudeCode.askUserQuestion : null;
48781
+ return askUserQuestion && isRecord$8(askUserQuestion.answers) ? askUserQuestion.answers : null;
48782
48782
  };
48783
48783
  function extractAskUserQuestionAnswersFromOutcome(meta, outcome) {
48784
- if (!outcome || !isRecord$7(outcome._meta)) return null;
48784
+ if (!outcome || !isRecord$8(outcome._meta)) return null;
48785
48785
  const rawAnswers = meta.source === "codex" ? getCodexOutcomeAnswers(outcome._meta) : getClaudeOutcomeAnswers(outcome._meta);
48786
48786
  if (!rawAnswers) return null;
48787
48787
  const result = {};
@@ -48790,7 +48790,7 @@ Task description:
48790
48790
  const raw2 = rawAnswers[key2];
48791
48791
  if (raw2 === void 0) continue;
48792
48792
  if (meta.source === "codex") {
48793
- if (!isRecord$7(raw2)) continue;
48793
+ if (!isRecord$8(raw2)) continue;
48794
48794
  const inner = raw2.answers;
48795
48795
  if (!Array.isArray(inner)) continue;
48796
48796
  const values = inner.filter((value) => typeof value === "string");
@@ -48806,20 +48806,20 @@ Task description:
48806
48806
  }
48807
48807
  return Object.keys(result).length > 0 ? result : null;
48808
48808
  }
48809
- const isEnumOption = (value) => isRecord$7(value) && typeof value.const === "string";
48809
+ const isEnumOption = (value) => isRecord$8(value) && typeof value.const === "string";
48810
48810
  const getEnumOptionSource = (prop) => {
48811
48811
  if (Array.isArray(prop.oneOf)) return prop.oneOf;
48812
48812
  if (Array.isArray(prop.enum)) return prop.enum;
48813
48813
  const items2 = prop.items;
48814
- if (isRecord$7(items2)) {
48814
+ if (isRecord$8(items2)) {
48815
48815
  if (Array.isArray(items2.anyOf)) return items2.anyOf;
48816
48816
  if (Array.isArray(items2.enum)) return items2.enum;
48817
48817
  }
48818
48818
  return null;
48819
48819
  };
48820
- const isQuestionProperty = (prop) => isRecord$7(prop) && getEnumOptionSource(prop) !== null;
48821
- const isFreeTextProperty = (prop) => isRecord$7(prop) && prop.type === "string" && !Array.isArray(prop.oneOf) && !Array.isArray(prop.enum);
48822
- const isMultiSelectProperty = (prop) => prop.type === "array" || isRecord$7(prop.items);
48820
+ const isQuestionProperty = (prop) => isRecord$8(prop) && getEnumOptionSource(prop) !== null;
48821
+ const isFreeTextProperty = (prop) => isRecord$8(prop) && prop.type === "string" && !Array.isArray(prop.oneOf) && !Array.isArray(prop.enum);
48822
+ const isMultiSelectProperty = (prop) => prop.type === "array" || isRecord$8(prop.items);
48823
48823
  const parseElicitationOptions = (source) => {
48824
48824
  const options = [];
48825
48825
  for (const entry of source) {
@@ -48844,9 +48844,9 @@ Task description:
48844
48844
  return options;
48845
48845
  };
48846
48846
  function parseAskUserQuestionElicitationRequest(request) {
48847
- if (!isRecord$7(request) || request.mode !== "form") return null;
48847
+ if (!isRecord$8(request) || request.mode !== "form") return null;
48848
48848
  const schema2 = request.requestedSchema;
48849
- if (!isRecord$7(schema2) || !isRecord$7(schema2.properties)) return null;
48849
+ if (!isRecord$8(schema2) || !isRecord$8(schema2.properties)) return null;
48850
48850
  const entries = Object.entries(schema2.properties);
48851
48851
  const questionEntries = entries.filter(([, prop]) => isQuestionProperty(prop));
48852
48852
  if (questionEntries.length === 0) return null;
@@ -48856,7 +48856,7 @@ Task description:
48856
48856
  const questions = [];
48857
48857
  const fieldKeys = [];
48858
48858
  for (const [key2, prop] of questionEntries) {
48859
- if (!isRecord$7(prop)) continue;
48859
+ if (!isRecord$8(prop)) continue;
48860
48860
  const source = getEnumOptionSource(prop);
48861
48861
  if (!source) continue;
48862
48862
  const header = typeof prop.title === "string" ? prop.title : "";
@@ -48889,7 +48889,7 @@ Task description:
48889
48889
  };
48890
48890
  }
48891
48891
  const answers = extractAskUserQuestionAnswersFromOutcome(elicitation.meta, {
48892
- _meta: isRecord$7(outcome._meta) ? outcome._meta : null
48892
+ _meta: isRecord$8(outcome._meta) ? outcome._meta : null
48893
48893
  });
48894
48894
  if (!answers) {
48895
48895
  return {
@@ -52309,7 +52309,7 @@ ${tailedOutput}` : null;
52309
52309
  ];
52310
52310
  const buildPreviewTunnelRefreshPath = (tunnelId) => `${PREVIEW_TUNNELS_API_PATH}/${encodeURIComponent(tunnelId)}/refresh`;
52311
52311
  const buildPreviewTunnelRevokePath = (tunnelId) => `${PREVIEW_TUNNELS_API_PATH}/${encodeURIComponent(tunnelId)}/revoke`;
52312
- const isRecord$6 = (value) => typeof value === "object" && value !== null;
52312
+ const isRecord$7 = (value) => typeof value === "object" && value !== null;
52313
52313
  const isString$2 = (value) => typeof value === "string";
52314
52314
  const isOptionalNumber = (value) => value === void 0 || typeof value === "number";
52315
52315
  const isOptionalBoolean = (value) => value === void 0 || typeof value === "boolean";
@@ -52317,11 +52317,11 @@ ${tailedOutput}` : null;
52317
52317
  const isStringArray$1 = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
52318
52318
  const isHeaderEntries = (value) => Array.isArray(value) && value.every((entry) => Array.isArray(entry) && entry.length === 2 && typeof entry[0] === "string" && typeof entry[1] === "string");
52319
52319
  const isPreviewTunnelBinaryPayloadStream = (value) => value === "request-body" || value === "response-body" || value === "websocket-frame";
52320
- const isPreviewResourceLimits = (value) => isRecord$6(value) && isPositiveInteger(value.maxRequestBodyBytes) && isPositiveInteger(value.maxResponseBodyBytes) && isPositiveInteger(value.maxRequestDurationMs);
52320
+ const isPreviewResourceLimits = (value) => isRecord$7(value) && isPositiveInteger(value.maxRequestBodyBytes) && isPositiveInteger(value.maxResponseBodyBytes) && isPositiveInteger(value.maxRequestDurationMs);
52321
52321
  const parseJsonRecord = (raw2) => {
52322
52322
  try {
52323
52323
  const parsed = JSON.parse(raw2);
52324
- return isRecord$6(parsed) ? parsed : null;
52324
+ return isRecord$7(parsed) ? parsed : null;
52325
52325
  } catch {
52326
52326
  return null;
52327
52327
  }
@@ -52360,8 +52360,209 @@ ${tailedOutput}` : null;
52360
52360
  const parsed = parseJsonRecord(raw2);
52361
52361
  return parsed && isPreviewTunnelServerMessage(parsed) ? parsed : null;
52362
52362
  };
52363
- const isPreviewTunnelCreateResponse = (value) => isRecord$6(value) && isString$2(value.tunnelId) && isString$2(value.publicUrl) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number" && (value.resourceLimits === void 0 || isPreviewResourceLimits(value.resourceLimits));
52364
- const isPreviewTunnelRefreshResponse = (value) => isRecord$6(value) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number";
52363
+ const isPreviewTunnelCreateResponse = (value) => isRecord$7(value) && isString$2(value.tunnelId) && isString$2(value.publicUrl) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number" && (value.resourceLimits === void 0 || isPreviewResourceLimits(value.resourceLimits));
52364
+ const isPreviewTunnelRefreshResponse = (value) => isRecord$7(value) && isString$2(value.websocketUrl) && isString$2(value.sessionToken) && typeof value.expiresAt === "number";
52365
+ const MACHINE_FLOCK_DOC_STREAM_SEGMENT = "mf";
52366
+ const getMachineFlockDocId = (workspaceId, machineId) => `${workspaceId}:${MACHINE_FLOCK_DOC_STREAM_SEGMENT}:${machineId}`;
52367
+ const machineFlockKeys = {
52368
+ dotlodyPath: () => [
52369
+ "dotlodyPath"
52370
+ ],
52371
+ archiveSessionCommand: (sessionId) => [
52372
+ "cmd",
52373
+ "archiveSession",
52374
+ sessionId
52375
+ ],
52376
+ deleteSessionCommand: (sessionId) => [
52377
+ "cmd",
52378
+ "deleteSession",
52379
+ sessionId
52380
+ ],
52381
+ localProject: (localProjectId) => [
52382
+ "localProject",
52383
+ localProjectId
52384
+ ],
52385
+ agentConfig: (agentConfigId) => [
52386
+ "agentConfig",
52387
+ agentConfigId
52388
+ ],
52389
+ agentConfigIndex: (agentConfigId) => [
52390
+ "agentConfigIndex",
52391
+ agentConfigId
52392
+ ],
52393
+ acpCapability: (cliType, agentType) => [
52394
+ "acpCapability",
52395
+ cliType,
52396
+ agentType
52397
+ ],
52398
+ rateLimit: (cliType, limitId) => [
52399
+ "rateLimit",
52400
+ cliType,
52401
+ limitId
52402
+ ]
52403
+ };
52404
+ const parseMachineFlockKey = (key2) => {
52405
+ if (key2.length === 1 && key2[0] === "dotlodyPath") {
52406
+ return {
52407
+ kind: "dotlodyPath",
52408
+ key: machineFlockKeys.dotlodyPath()
52409
+ };
52410
+ }
52411
+ if (key2.length === 3 && key2[0] === "cmd" && key2[1] === "archiveSession" && isNonEmptyString(key2[2])) {
52412
+ const sessionId = key2[2];
52413
+ return {
52414
+ kind: "archiveSessionCommand",
52415
+ key: machineFlockKeys.archiveSessionCommand(sessionId),
52416
+ sessionId
52417
+ };
52418
+ }
52419
+ if (key2.length === 3 && key2[0] === "cmd" && key2[1] === "deleteSession" && isNonEmptyString(key2[2])) {
52420
+ const sessionId = key2[2];
52421
+ return {
52422
+ kind: "deleteSessionCommand",
52423
+ key: machineFlockKeys.deleteSessionCommand(sessionId),
52424
+ sessionId
52425
+ };
52426
+ }
52427
+ if (key2.length === 2 && key2[0] === "localProject" && isNonEmptyString(key2[1])) {
52428
+ const localProjectId = key2[1];
52429
+ return {
52430
+ kind: "localProject",
52431
+ key: machineFlockKeys.localProject(localProjectId),
52432
+ localProjectId
52433
+ };
52434
+ }
52435
+ if (key2.length === 2 && key2[0] === "agentConfig" && isNonEmptyString(key2[1])) {
52436
+ const agentConfigId = key2[1];
52437
+ return {
52438
+ kind: "agentConfig",
52439
+ key: machineFlockKeys.agentConfig(agentConfigId),
52440
+ agentConfigId
52441
+ };
52442
+ }
52443
+ if (key2.length === 2 && key2[0] === "agentConfigIndex" && isNonEmptyString(key2[1])) {
52444
+ const agentConfigId = key2[1];
52445
+ return {
52446
+ kind: "agentConfigIndex",
52447
+ key: machineFlockKeys.agentConfigIndex(agentConfigId),
52448
+ agentConfigId
52449
+ };
52450
+ }
52451
+ if (key2.length === 3 && key2[0] === "acpCapability" && isAgentConfigCliType(key2[1]) && isNonEmptyString(key2[2])) {
52452
+ return {
52453
+ kind: "acpCapability",
52454
+ key: machineFlockKeys.acpCapability(key2[1], key2[2]),
52455
+ cliType: key2[1],
52456
+ agentType: key2[2]
52457
+ };
52458
+ }
52459
+ if (key2.length === 3 && key2[0] === "rateLimit" && isCliType(key2[1]) && isNonEmptyString(key2[2])) {
52460
+ return {
52461
+ kind: "rateLimit",
52462
+ key: machineFlockKeys.rateLimit(key2[1], key2[2]),
52463
+ cliType: key2[1],
52464
+ limitId: key2[2]
52465
+ };
52466
+ }
52467
+ return void 0;
52468
+ };
52469
+ const serializeMachineFlockKey = (key2) => JSON.stringify(key2);
52470
+ function readMachineFlockRowsFromFlock(flock) {
52471
+ const rows = {};
52472
+ for (const row of flock.scan()) {
52473
+ const parsed = parseMachineFlockRow(row.key, row.value);
52474
+ if (!parsed) {
52475
+ continue;
52476
+ }
52477
+ rows[serializeMachineFlockKey(parsed.key)] = parsed;
52478
+ }
52479
+ return rows;
52480
+ }
52481
+ function writeMachineFlockRowToFlock(flock, row, nowMs2) {
52482
+ const previous = readMachineFlockRowsFromFlock(flock)[serializeMachineFlockKey(row.key)];
52483
+ if (machineFlockRowsEqual(previous, row)) {
52484
+ return false;
52485
+ }
52486
+ flock.set(row.key, row.value, nowMs2);
52487
+ flock.commit();
52488
+ return true;
52489
+ }
52490
+ function deleteMachineFlockRowFromFlock(flock, key2, nowMs2) {
52491
+ const rowId = serializeMachineFlockKey(key2);
52492
+ const previous = readMachineFlockRowsFromFlock(flock)[rowId];
52493
+ if (!previous) {
52494
+ return false;
52495
+ }
52496
+ flock.delete(key2, nowMs2);
52497
+ flock.commit();
52498
+ return true;
52499
+ }
52500
+ function parseMachineFlockRow(key2, value) {
52501
+ const parsedKey = parseMachineFlockKey(key2);
52502
+ if (!parsedKey || value === void 0) {
52503
+ return void 0;
52504
+ }
52505
+ switch (parsedKey.kind) {
52506
+ case "dotlodyPath":
52507
+ return typeof value === "string" && value.trim() ? {
52508
+ key: parsedKey.key,
52509
+ value
52510
+ } : void 0;
52511
+ case "archiveSessionCommand":
52512
+ return isMachineArchiveSessionCommand(value) ? {
52513
+ key: parsedKey.key,
52514
+ value
52515
+ } : void 0;
52516
+ case "deleteSessionCommand":
52517
+ return isMachineDeleteSessionCommand(value) ? {
52518
+ key: parsedKey.key,
52519
+ value
52520
+ } : void 0;
52521
+ case "localProject":
52522
+ return isLocalProjectMeta(value) ? {
52523
+ key: parsedKey.key,
52524
+ value
52525
+ } : void 0;
52526
+ case "agentConfig":
52527
+ return isAgentConfigMeta(value) ? {
52528
+ key: parsedKey.key,
52529
+ value
52530
+ } : void 0;
52531
+ case "agentConfigIndex":
52532
+ return isAgentConfigListSummary(value) ? {
52533
+ key: parsedKey.key,
52534
+ value
52535
+ } : void 0;
52536
+ case "acpCapability":
52537
+ return isAcpCapabilityCacheEntry(value) ? {
52538
+ key: parsedKey.key,
52539
+ value
52540
+ } : void 0;
52541
+ case "rateLimit":
52542
+ return isRecord$6(value) ? {
52543
+ key: parsedKey.key,
52544
+ value
52545
+ } : void 0;
52546
+ }
52547
+ return void 0;
52548
+ }
52549
+ function machineFlockRowsEqual(left2, right2) {
52550
+ if (left2 === right2) return true;
52551
+ if (!left2 || !right2) return false;
52552
+ return serializeMachineFlockKey(left2.key) === serializeMachineFlockKey(right2.key) && JSON.stringify(left2.value) === JSON.stringify(right2.value);
52553
+ }
52554
+ const isRecord$6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
52555
+ const isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
52556
+ const isOptionalString = (value) => value === void 0 || typeof value === "string";
52557
+ const isStringRecord = (value) => isRecord$6(value) && Object.values(value).every((entry) => typeof entry === "string");
52558
+ const isCliType = (value) => value === "claude" || value === "codex";
52559
+ const isAgentConfigCliType = (value) => value === "builtin" || value === "registry" || value === "custom";
52560
+ const isMachineArchiveSessionCommand = (value) => isRecord$6(value) && value.v === 1 && typeof value.requestedAt === "number" && isOptionalString(value.requestedBy);
52561
+ const isMachineDeleteSessionCommand = (value) => isRecord$6(value) && value.v === 1 && typeof value.requestedAt === "number" && isOptionalString(value.repoFullName) && isOptionalString(value.branchName) && isOptionalString(value.baseBranchName) && isOptionalString(value.localProjectId) && isOptionalString(value.originalRootPath) && (value.isWorktree === void 0 || value.isWorktree === true) && isOptionalString(value.keptWorktreePath);
52562
+ const isLocalProjectMeta = (value) => isRecord$6(value) && isNonEmptyString(value.id) && isNonEmptyString(value.name) && isNonEmptyString(value.rootPath) && typeof value.createdAtMs === "number" && (value.lastOpenedAtMs === void 0 || typeof value.lastOpenedAtMs === "number");
52563
+ const isAgentConfigMeta = (value) => isRecord$6(value) && isNonEmptyString(value.id) && isNonEmptyString(value.machineId) && isNonEmptyString(value.name) && isOptionalString(value.description) && isAgentConfigCliType(value.cliType) && isNonEmptyString(value.agentType) && isStringRecord(value.env);
52564
+ const isAgentConfigListSummary = (value) => isRecord$6(value) && isNonEmptyString(value.id) && isNonEmptyString(value.machineId) && isNonEmptyString(value.name) && isOptionalString(value.description) && isAgentConfigCliType(value.cliType) && isNonEmptyString(value.agentType) && isOptionalString(value.brandId);
52565
+ const isAcpCapabilityCacheEntry = (value) => isRecord$6(value) && isAgentConfigCliType(value.cliType) && isNonEmptyString(value.agentType) && Array.isArray(value.modes) && Array.isArray(value.models) && typeof value.fetchedAt === "number";
52365
52566
  const LOCAL_MACHINE_RPC_PATH = "/machine-rpc";
52366
52567
  const BaseLocalMachineRpcRequestSchema = object$1({
52367
52568
  machineId: string$1().trim().min(1),
@@ -117002,6 +117203,34 @@ The file is not available yet and could not be downloaded; ask the user to resen
117002
117203
  if (!cliEntrypoint) {
117003
117204
  return [];
117004
117205
  }
117206
+ const env2 = [
117207
+ {
117208
+ name: "LODY_MCP_SESSION_ID",
117209
+ value: this.options.sessionId
117210
+ },
117211
+ {
117212
+ name: "LODY_MCP_WORKSPACE_ID",
117213
+ value: this.options.workspaceId
117214
+ },
117215
+ {
117216
+ name: "LODY_MCP_MACHINE_ID",
117217
+ value: this.options.machineId
117218
+ },
117219
+ {
117220
+ name: "LODY_MCP_LOCAL_CONTROL_PORT",
117221
+ value: String(LOCAL_SESSION_CONTROL_PORT)
117222
+ },
117223
+ {
117224
+ name: "LODY_MCP_WORKDIR",
117225
+ value: workdir
117226
+ }
117227
+ ];
117228
+ if (process.env.ELECTRON_RUN_AS_NODE) {
117229
+ env2.push({
117230
+ name: "ELECTRON_RUN_AS_NODE",
117231
+ value: process.env.ELECTRON_RUN_AS_NODE
117232
+ });
117233
+ }
117005
117234
  return [
117006
117235
  {
117007
117236
  name: "lody",
@@ -117011,28 +117240,7 @@ The file is not available yet and could not be downloaded; ask the user to resen
117011
117240
  "__internal",
117012
117241
  "lody-mcp-server"
117013
117242
  ],
117014
- env: [
117015
- {
117016
- name: "LODY_MCP_SESSION_ID",
117017
- value: this.options.sessionId
117018
- },
117019
- {
117020
- name: "LODY_MCP_WORKSPACE_ID",
117021
- value: this.options.workspaceId
117022
- },
117023
- {
117024
- name: "LODY_MCP_MACHINE_ID",
117025
- value: this.options.machineId
117026
- },
117027
- {
117028
- name: "LODY_MCP_LOCAL_CONTROL_PORT",
117029
- value: String(LOCAL_SESSION_CONTROL_PORT)
117030
- },
117031
- {
117032
- name: "LODY_MCP_WORKDIR",
117033
- value: workdir
117034
- }
117035
- ]
117243
+ env: env2
117036
117244
  }
117037
117245
  ];
117038
117246
  }
@@ -126956,7 +127164,7 @@ ${error2.message}` : execaMessage;
126956
127164
  const BuiltinACPSetting = {
126957
127165
  claude: {
126958
127166
  packageName: "acp-extension-claude",
126959
- version: "0.50.0",
127167
+ version: "0.54.1",
126960
127168
  binName: "acp-extension-claude"
126961
127169
  },
126962
127170
  codex: {
@@ -134538,16 +134746,13 @@ $mem | ConvertTo-Json -Compress
134538
134746
  userResolver;
134539
134747
  detachMetaRoomSyncedListener = null;
134540
134748
  bootstrapChain = Promise.resolve();
134749
+ startupBootstrapTimer = null;
134541
134750
  started = false;
134542
134751
  async start() {
134543
134752
  if (this.started) {
134544
134753
  return;
134545
134754
  }
134546
134755
  this.started = true;
134547
- await this.bootstrapOwnedSessions("startup");
134548
- if (!this.started) {
134549
- return;
134550
- }
134551
134756
  this.detachMetaRoomSyncedListener = this.deps.workspaceDocument.onMetaRoomSynced((reason) => {
134552
134757
  if (!this.started) {
134553
134758
  return;
@@ -134559,16 +134764,25 @@ $mem | ConvertTo-Json -Compress
134559
134764
  return;
134560
134765
  }
134561
134766
  const sessionId = event.docId.slice(SESSION_DOC_PREFIX.length);
134562
- this.reconcileSessionWatch(sessionId).catch((error2) => {
134563
- this.deps.logger.error(`[dispatch] Failed to reconcile session watch for ${sessionId}: ${formatErrorMessage(error2)}`);
134564
- });
134767
+ this.reconcileSessionWatch(sessionId, "metadata-watch").catch(() => void 0);
134565
134768
  }, {
134566
134769
  kinds: [
134567
134770
  "doc-metadata"
134568
134771
  ]
134569
134772
  });
134773
+ this.startupBootstrapTimer = setTimeout(() => {
134774
+ this.startupBootstrapTimer = null;
134775
+ if (this.started) {
134776
+ this.enqueueBootstrap("startup");
134777
+ }
134778
+ }, 0);
134779
+ this.startupBootstrapTimer.unref?.();
134570
134780
  }
134571
134781
  stop() {
134782
+ if (this.startupBootstrapTimer) {
134783
+ clearTimeout(this.startupBootstrapTimer);
134784
+ this.startupBootstrapTimer = null;
134785
+ }
134572
134786
  this.metadataWatchHandle?.unsubscribe();
134573
134787
  this.metadataWatchHandle = null;
134574
134788
  this.detachMetaRoomSyncedListener?.();
@@ -134633,6 +134847,13 @@ $mem | ConvertTo-Json -Compress
134633
134847
  return;
134634
134848
  }
134635
134849
  await this.bootstrapOwnedSessions(reason);
134850
+ if (reason === "startup" && this.started) {
134851
+ this.deps.onStartupBootstrapComplete?.();
134852
+ }
134853
+ }).catch((error2) => {
134854
+ this.deps.logger.error(`[dispatch] Owned-session bootstrap failed (reason=${reason}): ${formatErrorMessage(error2, {
134855
+ includeStack: true
134856
+ })}`);
134636
134857
  });
134637
134858
  this.bootstrapChain = next2;
134638
134859
  }
@@ -134647,11 +134868,20 @@ $mem | ConvertTo-Json -Compress
134647
134868
  this.deps.logger.debug(`[dispatch] Scanning owned sessions (reason=${reason})`);
134648
134869
  const flock = getMeta();
134649
134870
  const sessionRoomIds = /* @__PURE__ */ new Set();
134650
- for (const row of await flock.scan({
134651
- prefix: [
134652
- "m"
134653
- ]
134654
- })) {
134871
+ let rows;
134872
+ try {
134873
+ rows = await flock.scan({
134874
+ prefix: [
134875
+ "m"
134876
+ ]
134877
+ });
134878
+ } catch (error2) {
134879
+ this.deps.logger.error(`[dispatch] Failed to scan owned sessions (reason=${reason}): ${formatErrorMessage(error2, {
134880
+ includeStack: true
134881
+ })}`);
134882
+ return;
134883
+ }
134884
+ for (const row of rows) {
134655
134885
  const key2 = row.key;
134656
134886
  if (!Array.isArray(key2) || key2.length < 2) {
134657
134887
  continue;
@@ -134661,58 +134891,83 @@ $mem | ConvertTo-Json -Compress
134661
134891
  sessionRoomIds.add(roomId);
134662
134892
  }
134663
134893
  }
134894
+ this.deps.logger.debug(`[dispatch] Found ${sessionRoomIds.size} session room(s) during owned-session scan (reason=${reason})`);
134664
134895
  if (!this.started) {
134665
134896
  return;
134666
134897
  }
134667
- await Promise.all(Array.from(sessionRoomIds, async (roomId) => {
134898
+ const reconcileFailures = await Promise.all([
134899
+ ...sessionRoomIds
134900
+ ].map(async (roomId) => {
134668
134901
  if (!this.started) {
134669
- return;
134902
+ return false;
134670
134903
  }
134671
134904
  const sessionId = roomId.slice(SESSION_DOC_PREFIX.length);
134672
- await this.reconcileSessionWatch(sessionId);
134905
+ try {
134906
+ await this.reconcileSessionWatch(sessionId, `bootstrap:${reason}`);
134907
+ return false;
134908
+ } catch {
134909
+ return true;
134910
+ }
134673
134911
  }));
134912
+ const failedCount = reconcileFailures.filter(Boolean).length;
134913
+ if (failedCount > 0) {
134914
+ this.deps.logger.warn(`[dispatch] Owned-session bootstrap completed with ${failedCount}/${sessionRoomIds.size} session reconcile failure(s) (reason=${reason})`);
134915
+ }
134674
134916
  }
134675
- async reconcileSessionWatch(sessionId) {
134917
+ async reconcileSessionWatch(sessionId, trigger) {
134676
134918
  const roomId = getSessionRoomId(sessionId);
134677
- const record2 = await this.deps.workspaceDocument.repo.getDocMeta(roomId);
134678
- const meta = isLoroRepoDocDeleted(record2) ? void 0 : record2?.meta;
134679
- const isOwned = meta?.machineId === this.deps.machineId && !meta?.isArchived;
134680
- if (!isOwned) {
134681
- const watched = this.watchedSessions.get(sessionId);
134682
- watched?.unsubscribe();
134683
- this.watchedSessions.delete(sessionId);
134684
- this.cancelCheckChains.delete(sessionId);
134685
- this.goalCommandCheckChains.delete(sessionId);
134686
- this.cancelSeenTurn.delete(sessionId);
134687
- this.goalCommandSeenId.delete(sessionId);
134688
- this.interruptAccessRetry(sessionId);
134689
- return;
134690
- }
134691
- if (!this.sessionNeedsActiveWatch(meta)) {
134692
- const watched = this.watchedSessions.get(sessionId);
134693
- if (watched) {
134694
- watched.unsubscribe();
134919
+ let phase = "read-doc-meta";
134920
+ try {
134921
+ const record2 = await this.deps.workspaceDocument.repo.getDocMeta(roomId);
134922
+ const meta = isLoroRepoDocDeleted(record2) ? void 0 : record2?.meta;
134923
+ phase = "evaluate-ownership";
134924
+ const isOwned = meta?.machineId === this.deps.machineId && !meta?.isArchived;
134925
+ if (!isOwned) {
134926
+ const watched = this.watchedSessions.get(sessionId);
134927
+ watched?.unsubscribe();
134695
134928
  this.watchedSessions.delete(sessionId);
134696
- this.deps.logger.debug(`[${sessionId}] Unwatching idle session (no pending work)`);
134929
+ this.cancelCheckChains.delete(sessionId);
134930
+ this.goalCommandCheckChains.delete(sessionId);
134931
+ this.cancelSeenTurn.delete(sessionId);
134932
+ this.goalCommandSeenId.delete(sessionId);
134933
+ this.interruptAccessRetry(sessionId);
134934
+ return;
134697
134935
  }
134698
- this.interruptAccessRetry(sessionId);
134699
- return;
134700
- }
134701
- if (!this.watchedSessions.has(sessionId)) {
134702
- const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(sessionId);
134703
- const unsubscribe2 = sessionDoc.mirror?.subscribe(() => {
134704
- this.enqueueGoalCommandCheck(sessionId);
134705
- this.enqueueSessionCheck(sessionId);
134706
- });
134707
- if (unsubscribe2) {
134708
- this.watchedSessions.set(sessionId, {
134709
- unsubscribe: unsubscribe2
134936
+ phase = "evaluate-active-watch";
134937
+ if (!this.sessionNeedsActiveWatch(meta)) {
134938
+ const watched = this.watchedSessions.get(sessionId);
134939
+ if (watched) {
134940
+ watched.unsubscribe();
134941
+ this.watchedSessions.delete(sessionId);
134942
+ this.deps.logger.debug(`[${sessionId}] Unwatching idle session (no pending work)`);
134943
+ }
134944
+ this.interruptAccessRetry(sessionId);
134945
+ return;
134946
+ }
134947
+ if (!this.watchedSessions.has(sessionId)) {
134948
+ phase = "open-session-doc";
134949
+ const sessionDoc = await this.deps.workspaceDocument.getOrCreateSessionDoc(sessionId);
134950
+ phase = "subscribe-session-doc";
134951
+ const unsubscribe2 = sessionDoc.mirror?.subscribe(() => {
134952
+ this.enqueueGoalCommandCheck(sessionId);
134953
+ this.enqueueSessionCheck(sessionId);
134710
134954
  });
134955
+ if (unsubscribe2) {
134956
+ this.watchedSessions.set(sessionId, {
134957
+ unsubscribe: unsubscribe2
134958
+ });
134959
+ }
134711
134960
  }
134961
+ phase = "enqueue-session-checks";
134962
+ this.enqueueCancelCheck(sessionId);
134963
+ this.enqueueGoalCommandCheck(sessionId);
134964
+ this.enqueueSessionCheck(sessionId);
134965
+ } catch (error2) {
134966
+ this.deps.logger.error(`[dispatch] Failed to reconcile session watch (sessionId=${sessionId}, roomId=${roomId}, trigger=${trigger}, phase=${phase}): ${formatErrorMessage(error2, {
134967
+ includeStack: true
134968
+ })}`);
134969
+ throw error2;
134712
134970
  }
134713
- this.enqueueCancelCheck(sessionId);
134714
- this.enqueueGoalCommandCheck(sessionId);
134715
- this.enqueueSessionCheck(sessionId);
134716
134971
  }
134717
134972
  sessionNeedsActiveWatch(meta) {
134718
134973
  const statusType = meta.status?.type;
@@ -143563,6 +143818,71 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
143563
143818
  function delay$1(ms2) {
143564
143819
  return new Promise((resolve2) => setTimeout(resolve2, ms2));
143565
143820
  }
143821
+ function getMachineCommandEventImpact(events) {
143822
+ let archive = false;
143823
+ let deleteCommand = false;
143824
+ for (const event of events) {
143825
+ const parsed = parseMachineFlockKey(event.key);
143826
+ if (parsed?.kind === "archiveSessionCommand") {
143827
+ archive = true;
143828
+ }
143829
+ if (parsed?.kind === "deleteSessionCommand") {
143830
+ archive = true;
143831
+ deleteCommand = true;
143832
+ }
143833
+ }
143834
+ return {
143835
+ archive,
143836
+ delete: deleteCommand
143837
+ };
143838
+ }
143839
+ function getMachineFlockArchiveSessionIds(rows) {
143840
+ const sessionIds = [];
143841
+ for (const row of Object.values(rows)) {
143842
+ const parsed = parseMachineFlockKey(row.key);
143843
+ if (parsed?.kind === "archiveSessionCommand") {
143844
+ sessionIds.push(parsed.sessionId);
143845
+ }
143846
+ }
143847
+ return sessionIds;
143848
+ }
143849
+ function getMachineFlockDeleteEntries(rows) {
143850
+ const entries = [];
143851
+ for (const row of Object.values(rows)) {
143852
+ const parsed = parseMachineFlockKey(row.key);
143853
+ if (parsed?.kind === "deleteSessionCommand") {
143854
+ entries.push([
143855
+ parsed.sessionId,
143856
+ row.value
143857
+ ]);
143858
+ }
143859
+ }
143860
+ return entries;
143861
+ }
143862
+ function buildMachineCommandSnapshot(machineMeta, machineFlockRows) {
143863
+ const needToArchiveSessions = machineMeta?.needToArchiveSessions ?? {};
143864
+ const archiveSessionIds = Array.from(/* @__PURE__ */ new Set([
143865
+ ...Object.keys(needToArchiveSessions),
143866
+ ...getMachineFlockArchiveSessionIds(machineFlockRows)
143867
+ ]));
143868
+ const entriesBySessionId = /* @__PURE__ */ new Map();
143869
+ for (const [sessionId, request] of getMachineFlockDeleteEntries(machineFlockRows)) {
143870
+ entriesBySessionId.set(sessionId, request);
143871
+ }
143872
+ for (const [sessionId, request] of Object.entries(machineMeta?.needToDeleteSessions ?? {})) {
143873
+ if (!entriesBySessionId.has(sessionId)) {
143874
+ entriesBySessionId.set(sessionId, request);
143875
+ }
143876
+ }
143877
+ const deleteEntries = Array.from(entriesBySessionId.entries());
143878
+ return {
143879
+ machineMeta,
143880
+ machineFlockRows,
143881
+ archiveSessionIds,
143882
+ deleteEntries,
143883
+ deleteSessionIds: new Set(deleteEntries.map(([sessionId]) => sessionId))
143884
+ };
143885
+ }
143566
143886
  function formatLiveActivityUpdatedAt(value, nowMs2) {
143567
143887
  if (!Number.isFinite(value) || value <= 0) return "";
143568
143888
  const elapsedMs = Math.max(0, nowMs2 - value);
@@ -143893,6 +144213,13 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
143893
144213
  }
143894
144214
  },
143895
144215
  recordChatFailure: async (sessionDoc, reason, message) => await this.recordChatFailure(sessionDoc, reason, message),
144216
+ onStartupBootstrapComplete: () => {
144217
+ void this.resetMachineDisconnectedSessionsToIdle().catch((error2) => {
144218
+ this.logger.debug(`[dispatch] Failed to reset stale sessions after startup bootstrap: ${formatErrorMessage(error2, {
144219
+ includeStack: true
144220
+ })}`);
144221
+ });
144222
+ },
143896
144223
  onFatalAuthFailure: (error2) => this.onFatalAuthFailure?.(error2)
143897
144224
  });
143898
144225
  this.setupSessionEventHandlers();
@@ -143917,6 +144244,9 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
143917
144244
  archiveInFlight = /* @__PURE__ */ new Set();
143918
144245
  deleteWatchHandle = null;
143919
144246
  deleteInFlight = /* @__PURE__ */ new Set();
144247
+ machineFlockCommandWatcherPromise = null;
144248
+ machineFlockCommandUnsubscribe = null;
144249
+ machineFlockCommandRoomSub = null;
143920
144250
  sessionFileBackfillInFlight = /* @__PURE__ */ new Set();
143921
144251
  sessionFileBackfillStopped = false;
143922
144252
  detachCodeCollabMetaRoomSyncedListener = null;
@@ -145392,6 +145722,104 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
145392
145722
  })();
145393
145723
  });
145394
145724
  }
145725
+ getMachineFlockDocIdForMachine() {
145726
+ return getMachineFlockDocId(this.workspaceId, this.machineId);
145727
+ }
145728
+ getMachineFlockLogContext() {
145729
+ const docId = this.getMachineFlockDocIdForMachine();
145730
+ return `workspaceId=${this.workspaceId}, machineId=${this.machineId}, docId=${docId}`;
145731
+ }
145732
+ setupMachineFlockCommandWatcher() {
145733
+ if (this.machineFlockCommandWatcherPromise) {
145734
+ return;
145735
+ }
145736
+ const flockDocId = this.getMachineFlockDocIdForMachine();
145737
+ const flockContext = this.getMachineFlockLogContext();
145738
+ this.machineFlockCommandWatcherPromise = (async () => {
145739
+ const handle = await this.workspaceDocument.repo.openFlockDoc(flockDocId);
145740
+ this.machineFlockCommandUnsubscribe = handle.flock.subscribe((batch) => {
145741
+ const events = batch.events ?? [];
145742
+ const impact = getMachineCommandEventImpact(events);
145743
+ if (impact.archive) {
145744
+ void this.processArchiveRequests();
145745
+ }
145746
+ if (impact.delete) {
145747
+ void this.processDeleteRequests();
145748
+ }
145749
+ });
145750
+ this.machineFlockCommandRoomSub = await handle.joinRoom();
145751
+ void this.machineFlockCommandRoomSub.firstSyncedWithRemote.then(() => {
145752
+ void this.processArchiveRequests();
145753
+ void this.processDeleteRequests();
145754
+ }, (error2) => {
145755
+ this.logger.debug(`[machine-flock] Command room initial sync failed (${flockContext}): ${formatErrorMessage(error2, {
145756
+ includeStack: true
145757
+ })}`);
145758
+ });
145759
+ this.logger.debug(`[machine-flock] Command watcher registered (${flockContext})`);
145760
+ void this.processArchiveRequests();
145761
+ void this.processDeleteRequests();
145762
+ })().catch((error2) => {
145763
+ this.machineFlockCommandWatcherPromise = null;
145764
+ this.logger.error(`[machine-flock] Failed to start command watcher (${flockContext}): ${formatErrorMessage(error2, {
145765
+ includeStack: true
145766
+ })}`);
145767
+ });
145768
+ }
145769
+ async readMachineFlockCommandRows() {
145770
+ const handle = await this.workspaceDocument.repo.openFlockDoc(this.getMachineFlockDocIdForMachine());
145771
+ return readMachineFlockRowsFromFlock(handle.flock);
145772
+ }
145773
+ async tryReadMachineFlockCommandRows() {
145774
+ try {
145775
+ return await this.readMachineFlockCommandRows();
145776
+ } catch (error2) {
145777
+ this.logger.debug(`[machine-flock] Failed to read command rows; falling back to machine meta queues (${this.getMachineFlockLogContext()}): ${formatErrorMessage(error2, {
145778
+ includeStack: true
145779
+ })}`);
145780
+ return {};
145781
+ }
145782
+ }
145783
+ async readMachineCommandSnapshot() {
145784
+ const machineRoomId = getMachineRoomId(this.machineId);
145785
+ const [machineMetaDoc, machineFlockRows] = await Promise.all([
145786
+ this.workspaceDocument.repo.getDocMeta(machineRoomId),
145787
+ this.tryReadMachineFlockCommandRows()
145788
+ ]);
145789
+ return buildMachineCommandSnapshot(machineMetaDoc?.meta, machineFlockRows);
145790
+ }
145791
+ async deleteMachineFlockCommandRow(key2, nowMs2 = getServerNow()) {
145792
+ const handle = await this.workspaceDocument.repo.openFlockDoc(this.getMachineFlockDocIdForMachine());
145793
+ const changed = deleteMachineFlockRowFromFlock(handle.flock, key2, nowMs2);
145794
+ if (!changed) {
145795
+ return false;
145796
+ }
145797
+ await this.workspaceDocument.repo.flush();
145798
+ await handle.syncOnce();
145799
+ return true;
145800
+ }
145801
+ async writeMachineFlockRow(row, nowMs2 = getServerNow()) {
145802
+ const handle = await this.workspaceDocument.repo.openFlockDoc(this.getMachineFlockDocIdForMachine());
145803
+ const changed = writeMachineFlockRowToFlock(handle.flock, row, nowMs2);
145804
+ if (!changed) {
145805
+ return false;
145806
+ }
145807
+ await this.workspaceDocument.repo.flush();
145808
+ await handle.syncOnce();
145809
+ return true;
145810
+ }
145811
+ async publishMachineDotlodyPath() {
145812
+ try {
145813
+ await this.writeMachineFlockRow({
145814
+ key: machineFlockKeys.dotlodyPath(),
145815
+ value: path__default.join(os__default.homedir(), ".lody")
145816
+ });
145817
+ } catch (error2) {
145818
+ this.logger.debug(`[machine-flock] Failed to publish dotlodyPath (${this.getMachineFlockLogContext()}): ${formatErrorMessage(error2, {
145819
+ includeStack: true
145820
+ })}`);
145821
+ }
145822
+ }
145395
145823
  setupArchiveWatcher() {
145396
145824
  if (this.archiveWatchHandle) {
145397
145825
  return;
@@ -149242,7 +149670,6 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
149242
149670
  await this.handler.registerMachine();
149243
149671
  void this.handler.ensureMachineRegistered();
149244
149672
  await this.handler.startSessionDispatchWatcher();
149245
- void this.handler.resetMachineDisconnectedSessionsToIdle();
149246
149673
  void this.handler.scanAndBackfillLocalSessionFiles();
149247
149674
  this.options.logger.debug("Machine runtime initialized");
149248
149675
  return {
@@ -158992,7 +159419,9 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
158992
159419
  throw error2;
158993
159420
  }
158994
159421
  })().catch((error2) => {
158995
- const message = `[fleet] Failed to start workspace runtime ${workspace.id}: ${formatErrorMessage(error2)}`;
159422
+ const message = `[fleet] Failed to start workspace runtime ${workspace.id}: ${formatErrorMessage(error2, {
159423
+ includeStack: true
159424
+ })}`;
158996
159425
  this.logger.warn(message);
158997
159426
  this.runtimeStateReporter.upsertIssue({
158998
159427
  code: `workspace_start_failed:${workspace.id}`,
@@ -191902,7 +192331,7 @@ ${entry.text}`).join("\n\n");
191902
192331
  data = createReviewBundleSnapshot(bundle);
191903
192332
  }
191904
192333
  const { injectReviewSnapshot } = await import("./chunks/index-v46gaGAl.js");
191905
- const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-RQWEBiYD.js");
192334
+ const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-E8RZ96-t.js");
191906
192335
  const template = await resolveReviewViewerTemplate();
191907
192336
  const html = injectReviewSnapshot(template, data);
191908
192337
  const outputPath = options.output ? path__default$1.resolve(options.output) : defaultHtmlOutputPath(inputPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lody",
3
- "version": "0.65.0",
3
+ "version": "0.66.1",
4
4
  "description": "Lody Agent CLI tool for managing remote command execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "node": ">=18.0.0"
21
21
  },
22
22
  "optionalDependencies": {
23
- "acp-extension-claude": "0.50.0",
23
+ "acp-extension-claude": "0.54.1",
24
24
  "acp-extension-codex": "0.15.0"
25
25
  },
26
26
  "devDependencies": {
@@ -78,7 +78,7 @@
78
78
  "zod": "^4.1.5",
79
79
  "@lody/cli-supervisor": "0.0.1",
80
80
  "@lody/code-review-helper": "0.0.0",
81
- "lody-code-review-viewer": "0.65.0",
81
+ "lody-code-review-viewer": "0.66.1",
82
82
  "@lody/convex": "0.0.1",
83
83
  "@lody/loro-streams-rpc": "0.0.1",
84
84
  "@lody/shared": "0.0.1"
@@ -100,7 +100,7 @@
100
100
  "scripts": {
101
101
  "dev": "node dev.mjs",
102
102
  "dev:staging": "LODY_AUTH_URL=https://impressive-guineapig-165.convex.cloud LODY_AUTH_SITE_URL=https://impressive-guineapig-165.convex.site LODY_SERVER_URL=https://lody-server.zx-073.workers.dev SITE_URL=https://main.lody.pages.dev/ pnpm run dev",
103
- "dev:prod": "LODY_AUTH_URL=https://nautical-curlew-181.convex.cloud LODY_SERVER_URL=https://api.lody.ai pnpm run dev",
103
+ "dev:prod": "LODY_AUTH_URL=https://convex.lody.ai LODY_SERVER_URL=https://api.lody.ai pnpm run dev",
104
104
  "build": "pnpm run clean && pnpm run typecheck && pnpm run build:bundle && pnpm run check:published-bundle-imports && pnpm run copy:wasm",
105
105
  "build:watch": "pnpm run prepare:review-assets && vite build --watch",
106
106
  "build:bundle": "pnpm run prepare:review-assets && vite build",