lody 0.96.1 → 0.97.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
@@ -506,7 +506,7 @@ Upgrade Node, then re-run: npx lody@latest`;
506
506
  this._buckets = {};
507
507
  }
508
508
  }
509
- const DIGITS$1 = "0123456789abcdef";
509
+ const DIGITS = "0123456789abcdef";
510
510
  class UUID {
511
511
  constructor(bytes2) {
512
512
  this.bytes = bytes2;
@@ -568,8 +568,8 @@ Upgrade Node, then re-run: npx lody@latest`;
568
568
  toString() {
569
569
  let text = "";
570
570
  for (let i2 = 0; i2 < this.bytes.length; i2++) {
571
- text += DIGITS$1.charAt(this.bytes[i2] >>> 4);
572
- text += DIGITS$1.charAt(15 & this.bytes[i2]);
571
+ text += DIGITS.charAt(this.bytes[i2] >>> 4);
572
+ text += DIGITS.charAt(15 & this.bytes[i2]);
573
573
  if (3 === i2 || 5 === i2 || 7 === i2 || 9 === i2) text += "-";
574
574
  }
575
575
  return text;
@@ -577,8 +577,8 @@ Upgrade Node, then re-run: npx lody@latest`;
577
577
  toHex() {
578
578
  let text = "";
579
579
  for (let i2 = 0; i2 < this.bytes.length; i2++) {
580
- text += DIGITS$1.charAt(this.bytes[i2] >>> 4);
581
- text += DIGITS$1.charAt(15 & this.bytes[i2]);
580
+ text += DIGITS.charAt(this.bytes[i2] >>> 4);
581
+ text += DIGITS.charAt(15 & this.bytes[i2]);
582
582
  }
583
583
  return text;
584
584
  }
@@ -4326,7 +4326,7 @@ Upgrade Node, then re-run: npx lody@latest`;
4326
4326
  }
4327
4327
  const name$2 = "lody";
4328
4328
  const name$1 = "@lody/cli-cloud";
4329
- const version$a = "0.96.1";
4329
+ const version$a = "0.97.0";
4330
4330
  const type$2 = "module";
4331
4331
  const scripts = {
4332
4332
  "dev": "node dev.mjs",
@@ -9701,9 +9701,6 @@ Upgrade Node, then re-run: npx lody@latest`;
9701
9701
  mcpServerIds: schema.Any({
9702
9702
  required: false
9703
9703
  }),
9704
- taskToolsEnabled: schema.Boolean({
9705
- required: false
9706
- }),
9707
9704
  agentRoleId: agentRoleIdSchema,
9708
9705
  agentRoleRevision: schema.Number({
9709
9706
  required: false
@@ -11213,10 +11210,7 @@ Requirements:
11213
11210
  config2.configOptionValues ? Object.entries(config2.configOptionValues).sort(([left2], [right2]) => left2.localeCompare(right2)) : null,
11214
11211
  ...config2.mcpServerIds === void 0 ? [] : [
11215
11212
  normalizeMcpServerIdsForDedup(config2.mcpServerIds)
11216
- ],
11217
- ...config2.taskToolsEnabled === true ? [
11218
- true
11219
- ] : []
11213
+ ]
11220
11214
  ];
11221
11215
  }
11222
11216
  function normalizeSessionPreparationClaimIdentity(input2) {
@@ -11503,7 +11497,6 @@ Requirements:
11503
11497
  modelId: string$1().optional(),
11504
11498
  configOptionValues: AcpConfigOptionValuesSchema.optional(),
11505
11499
  mcpServerIds: array$2(string$1()).optional(),
11506
- taskToolsEnabled: boolean().optional(),
11507
11500
  agentRoleId: string$1().trim().min(1).nullable().optional(),
11508
11501
  agentRoleRevision: number$4().int().nonnegative().optional(),
11509
11502
  issuePRMentions: array$2(IssuePRMentionSchema).optional(),
@@ -11578,10 +11571,6 @@ Requirements:
11578
11571
  if (mcpServerIds) {
11579
11572
  normalized.mcpServerIds = mcpServerIds;
11580
11573
  }
11581
- const taskToolsEnabled = maybeParseField(boolean(), record2.taskToolsEnabled);
11582
- if (taskToolsEnabled !== void 0) {
11583
- normalized.taskToolsEnabled = taskToolsEnabled;
11584
- }
11585
11574
  if (record2.agentRoleId === null) {
11586
11575
  normalized.agentRoleId = null;
11587
11576
  } else {
@@ -11926,8 +11915,7 @@ Requirements:
11926
11915
  modeId: string$1().trim().min(1).optional(),
11927
11916
  modelId: string$1().trim().min(1).optional(),
11928
11917
  configOptionValues: AcpConfigOptionValuesSchema.transform((values) => Object.fromEntries(Object.entries(values).filter(([configId]) => !isSensitiveAcpConfigOptionId(configId)))).optional(),
11929
- mcpServerIds: array$2(string$1()).transform((ids2) => normalizeMcpServerIdSelection(ids2) ?? []).optional(),
11930
- taskToolsEnabled: boolean().optional()
11918
+ mcpServerIds: array$2(string$1()).transform((ids2) => normalizeMcpServerIdSelection(ids2) ?? []).optional()
11931
11919
  }).strict();
11932
11920
  const SessionPreparationSpecSchema = object$1({
11933
11921
  preparationId: SessionPreparationIdSchema,
@@ -14735,36 +14723,6 @@ Requirements:
14735
14723
  }
14736
14724
  return false;
14737
14725
  }
14738
- function resolveTaskProposalOnEntry(entry, proposalId, resolution) {
14739
- const items2 = Array.isArray(entry.items) ? entry.items : [];
14740
- for (const item of items2) {
14741
- const notice = asRecord$3(item);
14742
- if (notice?.type === "system_notice" && notice.name === "task_proposal" && asRecord$3(notice.meta)?.proposalId === proposalId) {
14743
- const meta = asRecord$3(notice.meta);
14744
- meta.outcome = resolution.outcome;
14745
- if (resolution.taskId !== void 0) meta.taskId = resolution.taskId;
14746
- return true;
14747
- }
14748
- }
14749
- return false;
14750
- }
14751
- function hasTaskProposal(entry, proposalId) {
14752
- const items2 = Array.isArray(entry.items) ? entry.items : [];
14753
- return items2.some((item) => {
14754
- const notice = asRecord$3(item);
14755
- return notice?.type === "system_notice" && notice.name === "task_proposal" && asRecord$3(notice.meta)?.proposalId === proposalId;
14756
- });
14757
- }
14758
- const TaskProposalResolutionSchema = object$1({
14759
- outcome: _enum$1([
14760
- "created",
14761
- "dismissed"
14762
- ]),
14763
- taskId: string$1().optional()
14764
- }).strict();
14765
- function parseTaskProposalResolution(value) {
14766
- return parseHistoryWrite(TaskProposalResolutionSchema, value);
14767
- }
14768
14726
  function resolveEditableTail(turns, expectedUserTurnId) {
14769
14727
  let userIndex = -1;
14770
14728
  for (let index = turns.length - 1; index >= 0; index -= 1) {
@@ -15397,85 +15355,7 @@ Requirements:
15397
15355
  const getLoroPreviewCommentStreamId = (workspaceId, sessionId) => `${workspaceId}:${LORO_PREVIEW_COMMENT_STREAM_SEGMENT}:${sessionId}`;
15398
15356
  const TASK_DOC_PREFIX = "task-";
15399
15357
  const LORO_TASK_STREAM_SEGMENT = "tk";
15400
- const getTaskRoomId = (taskId) => `${TASK_DOC_PREFIX}${taskId}`;
15401
- const isTaskDocRoomId = (roomId) => roomId.startsWith(TASK_DOC_PREFIX);
15402
- const getTaskIdFromRoomId = (roomId) => isTaskDocRoomId(roomId) ? roomId.slice(TASK_DOC_PREFIX.length) : null;
15403
15358
  const getLoroTaskStreamId = (workspaceId, taskId) => `${workspaceId}:${LORO_TASK_STREAM_SEGMENT}:${taskId}`;
15404
- const TASK_STATUS_VALUES = [
15405
- "backlog",
15406
- "todo",
15407
- "in_progress",
15408
- "needs_review",
15409
- "done",
15410
- "canceled"
15411
- ];
15412
- const TASK_PRIORITY_VALUES = [
15413
- "urgent",
15414
- "high",
15415
- "medium",
15416
- "low"
15417
- ];
15418
- const TASK_LABEL_MAX_LENGTH = 32;
15419
- const TASK_LABEL_MAX_COUNT = 10;
15420
- const normalizeTaskLabel = (raw2) => raw2.trim().toLowerCase().slice(0, TASK_LABEL_MAX_LENGTH);
15421
- const normalizeTaskLabels = (raw2) => {
15422
- if (!raw2) return [];
15423
- const seen = /* @__PURE__ */ new Set();
15424
- for (const value of raw2) {
15425
- const label2 = normalizeTaskLabel(value);
15426
- if (label2) seen.add(label2);
15427
- if (seen.size >= TASK_LABEL_MAX_COUNT) break;
15428
- }
15429
- return [
15430
- ...seen
15431
- ];
15432
- };
15433
- const TASK_TITLE_FALLBACK_MAX_LENGTH = 80;
15434
- const deriveTaskTitle = (input2) => {
15435
- const explicit = (input2.title ?? "").replace(/[\r\n]+/g, " ").trim();
15436
- if (explicit) {
15437
- return explicit;
15438
- }
15439
- const firstLine = (input2.body ?? "").split("\n").map((line3) => line3.trim()).find((line3) => line3.length > 0);
15440
- if (!firstLine) {
15441
- return "";
15442
- }
15443
- if (firstLine.length <= TASK_TITLE_FALLBACK_MAX_LENGTH) {
15444
- return firstLine;
15445
- }
15446
- return `${firstLine.slice(0, TASK_TITLE_FALLBACK_MAX_LENGTH).trimEnd()}\u2026`;
15447
- };
15448
- const isEmptyTaskDraft = (input2) => (input2.title ?? "").trim().length === 0 && (input2.body ?? "").trim().length === 0;
15449
- const getActiveTaskLinks = (links) => links.filter((link2) => link2.removedAt === void 0);
15450
- const getActiveTaskSessionLinks = (links) => getActiveTaskLinks(links).filter((link2) => link2.kind === "session" && Boolean(link2.sessionId));
15451
- const getActiveTaskPrLinks = (links) => getActiveTaskLinks(links).filter((link2) => link2.kind === "pr" && Boolean(link2.url));
15452
- const summarizeTaskMentions = (timeline) => {
15453
- let lastCommentAt;
15454
- const mentioned = /* @__PURE__ */ new Set();
15455
- for (const entry of timeline) {
15456
- if (entry.kind !== "comment") {
15457
- continue;
15458
- }
15459
- if (lastCommentAt === void 0 || entry.createdAt > lastCommentAt) {
15460
- lastCommentAt = entry.createdAt;
15461
- }
15462
- for (const userId of entry.mentions ?? []) {
15463
- if (userId) {
15464
- mentioned.add(userId);
15465
- }
15466
- }
15467
- }
15468
- return {
15469
- ...lastCommentAt !== void 0 ? {
15470
- lastCommentAt
15471
- } : {},
15472
- ...mentioned.size > 0 ? {
15473
- mentionedUserIds: [
15474
- ...mentioned
15475
- ]
15476
- } : {}
15477
- };
15478
- };
15479
15359
  const ACP_FAST_MODE_CONFIG_IDS = [
15480
15360
  "fast-mode",
15481
15361
  "fast"
@@ -15672,7 +15552,7 @@ Requirements:
15672
15552
  }
15673
15553
  const WORKSPACE_API_PATH_PREFIX = "/api/workspaces";
15674
15554
  const SESSION_IMAGE_UPLOAD_API_PATH = "/session-images/upload";
15675
- const trimTrailingSlash$2 = (url) => {
15555
+ const trimTrailingSlash$1 = (url) => {
15676
15556
  if (!url.endsWith("/")) {
15677
15557
  return url;
15678
15558
  }
@@ -15685,14 +15565,8 @@ Requirements:
15685
15565
  return `${WORKSPACE_API_PATH_PREFIX}/${encodeURIComponent(workspaceId)}/session-images/${encodeURIComponent(sessionId)}/${encodeURIComponent(imageId)}`;
15686
15566
  };
15687
15567
  const buildSessionImageApiUrl = (apiBaseUrl, apiPath) => {
15688
- return `${trimTrailingSlash$2(apiBaseUrl)}${apiPath}`;
15689
- };
15690
- const TASK_IMAGE_UPLOAD_API_PATH = "/task-images/upload";
15691
- const TASK_IMAGE_MARKDOWN_PROTOCOL = "lody-image://";
15692
- const trimTrailingSlash$1 = (url) => url.endsWith("/") ? url.slice(0, -1) : url;
15693
- const getTaskImageUploadApiPath = (workspaceId) => `/api/workspaces/${encodeURIComponent(workspaceId)}${TASK_IMAGE_UPLOAD_API_PATH}`;
15694
- const buildTaskImageApiUrl = (apiBaseUrl, apiPath) => `${trimTrailingSlash$1(apiBaseUrl)}${apiPath}`;
15695
- const buildTaskImageMarkdownUrl = (imageId) => `${TASK_IMAGE_MARKDOWN_PROTOCOL}${imageId}`;
15568
+ return `${trimTrailingSlash$1(apiBaseUrl)}${apiPath}`;
15569
+ };
15696
15570
  const SESSION_FILE_OBJECT_PREFIX = "session-files";
15697
15571
  const SESSION_FILE_PART_SIZE_BYTES = 16 * 1024 * 1024;
15698
15572
  const trimTrailingSlash = (url) => {
@@ -22869,9 +22743,6 @@ ${tailedOutput}` : null;
22869
22743
  ...inputConfig.mcpServerIds ? {
22870
22744
  mcpServerIds: inputConfig.mcpServerIds
22871
22745
  } : {},
22872
- ...typeof inputConfig.taskToolsEnabled === "boolean" ? {
22873
- taskToolsEnabled: inputConfig.taskToolsEnabled
22874
- } : {},
22875
22746
  ...inputConfig.agentRoleId !== void 0 ? {
22876
22747
  agentRoleId: inputConfig.agentRoleId
22877
22748
  } : {},
@@ -22899,7 +22770,6 @@ ${tailedOutput}` : null;
22899
22770
  return resolved;
22900
22771
  };
22901
22772
  const resolveSessionMcpSelection = (history, messageQueue = []) => resolveSessionConversationConfig(history, messageQueue).mcpServerIds ?? [];
22902
- const resolveSessionTaskToolsEnabled = (history, messageQueue = []) => resolveSessionConversationConfig(history, messageQueue).taskToolsEnabled === true;
22903
22773
  const normalizeTextInputBlock = (block) => {
22904
22774
  const trimmed2 = block.text.trim();
22905
22775
  if (!trimmed2) return null;
@@ -23141,9 +23011,6 @@ ${tailedOutput}` : null;
23141
23011
  mcpServerIds: args2.mcpServerIds ? [
23142
23012
  ...args2.mcpServerIds
23143
23013
  ] : void 0,
23144
- ...args2.taskToolsEnabled !== void 0 ? {
23145
- taskToolsEnabled: args2.taskToolsEnabled === true
23146
- } : {},
23147
23014
  ...args2.agentRoleId !== void 0 ? {
23148
23015
  agentRoleId: args2.agentRoleId
23149
23016
  } : {},
@@ -23175,326 +23042,6 @@ ${tailedOutput}` : null;
23175
23042
  finished: true
23176
23043
  };
23177
23044
  };
23178
- const taskMetaSchema = schema.LoroMap({
23179
- taskId: schema.String(),
23180
- title: schema.String(),
23181
- status: schema.String(),
23182
- ownerId: schema.String(),
23183
- order: schema.String(),
23184
- priority: schema.String({
23185
- required: false
23186
- }),
23187
- labels: schema.Any({
23188
- required: false
23189
- }),
23190
- agent: schema.Any({
23191
- required: false
23192
- }),
23193
- projects: schema.Any({
23194
- required: false
23195
- }),
23196
- lastRunConfig: schema.Any({
23197
- required: false
23198
- }),
23199
- createdAt: schema.Number(),
23200
- updatedAt: schema.Number(),
23201
- createdBy: schema.String({
23202
- required: false
23203
- })
23204
- });
23205
- const taskLinkSchema = schema.LoroMap({
23206
- id: schema.String(),
23207
- kind: schema.String(),
23208
- actorKind: schema.String(),
23209
- actorId: schema.String({
23210
- required: false
23211
- }),
23212
- actorName: schema.String({
23213
- required: false
23214
- }),
23215
- linkedAt: schema.Number(),
23216
- removedAt: schema.Number({
23217
- required: false
23218
- }),
23219
- sessionId: schema.String({
23220
- required: false
23221
- }),
23222
- origin: schema.String({
23223
- required: false
23224
- }),
23225
- parentSessionId: schema.String({
23226
- required: false
23227
- }),
23228
- provider: schema.String({
23229
- required: false
23230
- }),
23231
- url: schema.String({
23232
- required: false
23233
- }),
23234
- originSessionId: schema.String({
23235
- required: false
23236
- })
23237
- });
23238
- const taskTimelineEntrySchema = schema.LoroMap({
23239
- id: schema.String(),
23240
- kind: schema.String(),
23241
- actorKind: schema.String(),
23242
- actorId: schema.String({
23243
- required: false
23244
- }),
23245
- actorName: schema.String({
23246
- required: false
23247
- }),
23248
- createdAt: schema.Number(),
23249
- body: schema.String({
23250
- required: false
23251
- }),
23252
- mentions: schema.LoroList(schema.String(), void 0, {
23253
- required: false
23254
- }),
23255
- agentMentions: schema.LoroList(schema.String(), void 0, {
23256
- required: false
23257
- }),
23258
- dispatchedSessionId: schema.String({
23259
- required: false
23260
- }),
23261
- originSessionId: schema.String({
23262
- required: false
23263
- }),
23264
- quote: schema.String({
23265
- required: false
23266
- }),
23267
- anchor: schema.String({
23268
- required: false
23269
- }),
23270
- activityType: schema.String({
23271
- required: false
23272
- }),
23273
- activityData: schema.Any({
23274
- required: false
23275
- })
23276
- });
23277
- const taskDocSchema = schema({
23278
- meta: taskMetaSchema,
23279
- body: schema.LoroText(),
23280
- links: schema.LoroList(taskLinkSchema, (item) => item.id),
23281
- timeline: schema.LoroList(taskTimelineEntrySchema, (item) => item.id)
23282
- });
23283
- const TASK_INDEX_FLOCK_STREAM_SEGMENT = "ti";
23284
- const getTaskIndexFlockDocId = (workspaceId) => `${workspaceId}:${TASK_INDEX_FLOCK_STREAM_SEGMENT}`;
23285
- const TASK_INDEX_ROW_FAMILY = "task";
23286
- const taskIndexKeys = {
23287
- task: (taskId) => [
23288
- TASK_INDEX_ROW_FAMILY,
23289
- taskId
23290
- ]
23291
- };
23292
- const getTaskIndexScanPrefix = () => [
23293
- TASK_INDEX_ROW_FAMILY
23294
- ];
23295
- const TaskIndexRowSchema = object$1({
23296
- taskId: string$1().trim().min(1),
23297
- title: string$1(),
23298
- status: _enum$1(TASK_STATUS_VALUES),
23299
- ownerId: string$1(),
23300
- order: string$1().min(1),
23301
- priority: _enum$1(TASK_PRIORITY_VALUES).optional(),
23302
- labels: array$2(string$1()).optional(),
23303
- hasAgent: boolean().optional(),
23304
- agentConfigId: string$1().optional(),
23305
- projectKind: _enum$1([
23306
- "local",
23307
- "github"
23308
- ]).optional(),
23309
- projectKey: string$1().optional(),
23310
- ready: boolean().optional(),
23311
- sessionCount: number$4().int().nonnegative().optional(),
23312
- prCount: number$4().int().nonnegative().optional(),
23313
- lastCommentAt: number$4().optional(),
23314
- mentionedUserIds: array$2(string$1()).optional(),
23315
- createdAt: number$4(),
23316
- updatedAt: number$4(),
23317
- deletedAt: number$4().optional()
23318
- }).strip();
23319
- const parseTaskIndexRow = (value) => {
23320
- const parsed = TaskIndexRowSchema.safeParse(value);
23321
- return parsed.success ? parsed.data : void 0;
23322
- };
23323
- const parseTaskIndexKey = (key2) => {
23324
- if (key2.length !== 2) {
23325
- return void 0;
23326
- }
23327
- if (key2[0] !== TASK_INDEX_ROW_FAMILY) {
23328
- return void 0;
23329
- }
23330
- const taskId = key2[1];
23331
- return typeof taskId === "string" && taskId.length > 0 ? taskId : void 0;
23332
- };
23333
- const readTaskIndexRows = (scanned) => {
23334
- const rows = {};
23335
- for (const row of scanned) {
23336
- const taskId = parseTaskIndexKey(row.key);
23337
- if (!taskId) {
23338
- continue;
23339
- }
23340
- const parsed = parseTaskIndexRow(row.value);
23341
- if (!parsed || parsed.taskId !== taskId) {
23342
- continue;
23343
- }
23344
- rows[taskId] = parsed;
23345
- }
23346
- return rows;
23347
- };
23348
- const listVisibleTaskIndexRows = (rows) => Object.values(rows).filter((row) => row.deletedAt === void 0);
23349
- const countTaskLinks = (links) => {
23350
- let sessionCount = 0;
23351
- let prCount = 0;
23352
- for (const link2 of links) {
23353
- if (link2.removedAt !== void 0) {
23354
- continue;
23355
- }
23356
- if (link2.kind === "session") {
23357
- sessionCount += 1;
23358
- } else if (link2.kind === "pr") {
23359
- prCount += 1;
23360
- }
23361
- }
23362
- return {
23363
- sessionCount,
23364
- prCount
23365
- };
23366
- };
23367
- const summarizeTaskProject = (projects) => {
23368
- const first2 = projects?.[0];
23369
- if (!first2) return {};
23370
- if (first2.kind === "github" && first2.repoFullName) {
23371
- return {
23372
- projectKind: "github",
23373
- projectKey: first2.repoFullName
23374
- };
23375
- }
23376
- if (first2.kind === "local" && first2.localProjectId) {
23377
- return {
23378
- projectKind: "local",
23379
- projectKey: first2.localProjectId
23380
- };
23381
- }
23382
- return {};
23383
- };
23384
- const buildTaskIndexRow = (source, counts, mentions = {}) => ({
23385
- taskId: source.taskId,
23386
- title: source.title,
23387
- status: source.status,
23388
- ownerId: source.ownerId,
23389
- order: source.order,
23390
- ...source.priority ? {
23391
- priority: source.priority
23392
- } : {},
23393
- ...source.labels && source.labels.length > 0 ? {
23394
- labels: normalizeTaskLabels(source.labels)
23395
- } : {},
23396
- hasAgent: Boolean(source.agent),
23397
- ...source.agent ? {
23398
- agentConfigId: source.agent.agentConfigId
23399
- } : {},
23400
- ...summarizeTaskProject(source.projects),
23401
- ready: source.agent ? (source.projects?.length ?? 0) > 0 : true,
23402
- sessionCount: counts.sessionCount,
23403
- prCount: counts.prCount,
23404
- ...mentions.lastCommentAt !== void 0 ? {
23405
- lastCommentAt: mentions.lastCommentAt
23406
- } : {},
23407
- ...mentions.mentionedUserIds && mentions.mentionedUserIds.length > 0 ? {
23408
- mentionedUserIds: mentions.mentionedUserIds
23409
- } : {},
23410
- createdAt: source.createdAt,
23411
- updatedAt: source.updatedAt
23412
- });
23413
- const DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
23414
- const FIRST_DIGIT = DIGITS.charAt(0);
23415
- const LAST_DIGIT = DIGITS.charAt(DIGITS.length - 1);
23416
- const TASK_ORDER_MIN_KEY = DIGITS.charAt(1);
23417
- const digitIndex = (digit) => {
23418
- const index = digit === void 0 ? -1 : DIGITS.indexOf(digit);
23419
- if (index < 0) {
23420
- throw new Error(`invalid order key digit: ${digit}`);
23421
- }
23422
- return index;
23423
- };
23424
- const digitAt = (value, index) => {
23425
- const digit = value[index];
23426
- if (digit === void 0) {
23427
- throw new Error(`order key index out of range: ${value}[${index}]`);
23428
- }
23429
- return digit;
23430
- };
23431
- const assertValidKey = (key2, label2) => {
23432
- if (key2.length === 0) {
23433
- throw new Error(`${label2} order key must not be empty`);
23434
- }
23435
- if (key2.endsWith(FIRST_DIGIT)) {
23436
- throw new Error(`${label2} order key must not end with '${FIRST_DIGIT}': ${key2}`);
23437
- }
23438
- for (const digit of key2) {
23439
- digitIndex(digit);
23440
- }
23441
- };
23442
- const midpoint = (before, after2) => {
23443
- const beforeDigit = before.length > 0 ? digitIndex(before[0]) : 0;
23444
- const afterDigit = DIGITS.length;
23445
- if (afterDigit - beforeDigit > 1) {
23446
- return digitAt(DIGITS, Math.round((beforeDigit + afterDigit) / 2));
23447
- }
23448
- return digitAt(DIGITS, beforeDigit) + midpoint(before.slice(1));
23449
- };
23450
- const appendJitter = (key2, after2, random2) => {
23451
- if (!random2) {
23452
- return key2;
23453
- }
23454
- const value = random2();
23455
- if (!Number.isFinite(value)) {
23456
- return key2;
23457
- }
23458
- let highest = DIGITS.length - 1;
23459
- if (highest < 1) {
23460
- return key2;
23461
- }
23462
- const clamped = Math.min(Math.max(value, 0), 0.999999);
23463
- const index = 1 + Math.floor(clamped * highest);
23464
- return key2 + digitAt(DIGITS, Math.min(index, highest));
23465
- };
23466
- const generateTaskOrderKeyBetween = (before, after2, random2) => {
23467
- if (before !== null) {
23468
- assertValidKey(before, "before");
23469
- }
23470
- if (before === null && after2 === null) {
23471
- return appendJitter(TASK_ORDER_MIN_KEY, null, random2);
23472
- }
23473
- if (before !== null && after2 === null) {
23474
- const head2 = before.slice(0, -1);
23475
- const tail2 = digitAt(before, before.length - 1);
23476
- if (tail2 !== LAST_DIGIT) {
23477
- return appendJitter(head2 + digitAt(DIGITS, digitIndex(tail2) + 1), null, random2);
23478
- }
23479
- return appendJitter(`${before}${digitAt(DIGITS, 1)}`, null, random2);
23480
- }
23481
- return appendJitter(midpoint(before), after2, random2);
23482
- };
23483
- const generateTaskOrderKeyAtEnd = (existingKeys, random2) => {
23484
- let max2 = null;
23485
- for (const key2 of existingKeys) {
23486
- if (key2.length > 0 && (max2 === null || key2 > max2)) {
23487
- max2 = key2;
23488
- }
23489
- }
23490
- return generateTaskOrderKeyBetween(max2, null, random2);
23491
- };
23492
- const compareTaskOrder = (a, b) => {
23493
- if (a.order !== b.order) {
23494
- return a.order < b.order ? -1 : 1;
23495
- }
23496
- return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
23497
- };
23498
23045
  const REVIEW_POLICY_FLOCK_STREAM_SEGMENT = "rp";
23499
23046
  const getReviewPolicyFlockDocId = (workspaceId) => `${workspaceId}:${REVIEW_POLICY_FLOCK_STREAM_SEGMENT}`;
23500
23047
  const REVIEW_POLICY_ROW_FAMILY = "policy";
@@ -66068,8 +65615,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
66068
65615
  "cliType",
66069
65616
  "agentType",
66070
65617
  "mcpServerIds",
66071
- "configOptionValues",
66072
- "taskToolsEnabled"
65618
+ "configOptionValues"
66073
65619
  ];
66074
65620
  const parseCursor = (cursor, total) => {
66075
65621
  if (cursor === void 0) return total;
@@ -66351,95 +65897,6 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
66351
65897
  })
66352
65898
  });
66353
65899
  }
66354
- class HistoryActionRefused extends Error {
66355
- constructor(code2, message) {
66356
- super(message);
66357
- this.code = code2;
66358
- }
66359
- }
66360
- const sameActor = (current2, desired) => current2?.kind === desired?.kind && current2?.agentConfigId === desired?.agentConfigId && current2?.name === desired?.name;
66361
- const samePendingProposal = (current2, desired) => current2.proposalId === desired.proposalId && current2.title === desired.title && current2.body === desired.body && current2.outcome === void 0 && current2.taskId === void 0 && sameActor(current2.proposedBy, desired.proposedBy);
66362
- function planTaskProposal(history, turnId, desiredMeta, timestamp2) {
66363
- const desiredItem = {
66364
- type: "system_notice",
66365
- name: "task_proposal",
66366
- meta: desiredMeta
66367
- };
66368
- let changed = false;
66369
- let result = {
66370
- pending: true
66371
- };
66372
- const apply = () => {
66373
- const existingIndex = history.findIndex((entry) => entry.id === turnId);
66374
- if (existingIndex < 0) {
66375
- changed = true;
66376
- return [
66377
- ...history,
66378
- {
66379
- id: turnId,
66380
- role: "system",
66381
- timestamp: timestamp2,
66382
- items: [
66383
- desiredItem
66384
- ],
66385
- fileDiff: [],
66386
- finished: true
66387
- }
66388
- ];
66389
- }
66390
- const existing = history[existingIndex];
66391
- const proposalItemIndex = existing?.items?.findIndex((item) => item.type === "system_notice" && item.name === "task_proposal");
66392
- const proposalItem = proposalItemIndex !== void 0 && proposalItemIndex >= 0 ? existing?.items?.[proposalItemIndex] : void 0;
66393
- const existingMetaValue = proposalItem?.type === "system_notice" && proposalItem.name === "task_proposal" ? proposalItem.meta : void 0;
66394
- const parsedExistingMeta = TaskProposalMetaSchema.safeParse(existingMetaValue);
66395
- const existingMeta = parsedExistingMeta.success ? parsedExistingMeta.data : void 0;
66396
- if (!existing || proposalItemIndex === void 0 || proposalItemIndex < 0 || !existingMeta) {
66397
- throw new HistoryActionRefused("TASK_PROPOSAL_ID_CONFLICT", `History entry ${turnId} exists but is not a task proposal. Use a different proposalId.`);
66398
- }
66399
- if (existingMeta.proposalId !== desiredMeta.proposalId) {
66400
- throw new HistoryActionRefused("TASK_PROPOSAL_ID_CONFLICT", `History entry ${turnId} belongs to a different proposal. Use a different proposalId.`);
66401
- }
66402
- if (existingMeta.outcome === "created") {
66403
- result = {
66404
- pending: false,
66405
- outcome: "created",
66406
- ...existingMeta.taskId ? {
66407
- taskId: existingMeta.taskId
66408
- } : {}
66409
- };
66410
- return history;
66411
- }
66412
- if (existingMeta.outcome === "dismissed") {
66413
- result = {
66414
- pending: false,
66415
- outcome: "dismissed"
66416
- };
66417
- return history;
66418
- }
66419
- if (samePendingProposal(existingMeta, desiredMeta)) {
66420
- return history;
66421
- }
66422
- const items2 = [
66423
- ...existing.items ?? []
66424
- ];
66425
- items2[proposalItemIndex] = desiredItem;
66426
- const nextHistory = [
66427
- ...history
66428
- ];
66429
- nextHistory[existingIndex] = {
66430
- ...existing,
66431
- items: items2
66432
- };
66433
- changed = true;
66434
- return nextHistory;
66435
- };
66436
- const turns = apply();
66437
- return {
66438
- turns,
66439
- matched: changed,
66440
- proposal: result
66441
- };
66442
- }
66443
65900
  const sanitizeToolCallContentForHistory = (content, kind) => {
66444
65901
  if (!content) return void 0;
66445
65902
  const filtered = stripToolCallContentForHistory(kind ?? null, content);
@@ -66519,8 +65976,6 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
66519
65976
  matched: turns !== history
66520
65977
  };
66521
65978
  }
66522
- case "task-proposal":
66523
- return planTaskProposal(history, action.turnId, action.meta, action.timestamp);
66524
65979
  case "upsert-goal": {
66525
65980
  let replaced = false;
66526
65981
  for (const entry of history) entry.items = entry.items?.flatMap((item) => {
@@ -67075,7 +66530,6 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
67075
66530
  const normalized = normalizeSessionTurnInputConfig({
67076
66531
  mcpServerIds: picked.mcpServerIds,
67077
66532
  configOptionValues: picked.configOptionValues,
67078
- taskToolsEnabled: picked.taskToolsEnabled,
67079
66533
  cliType: picked.cliType,
67080
66534
  agentType: picked.agentType
67081
66535
  });
@@ -67378,18 +66832,15 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
67378
66832
  const commands = {
67379
66833
  async applyHistoryAction(action) {
67380
66834
  let matched = action.kind === "user-status" && action.requeueUndelivered === true;
67381
- let proposal;
67382
66835
  const apply = (entries) => {
67383
66836
  const result = applyHistoryAction(entries, action);
67384
66837
  matched = result.matched;
67385
- proposal = result.proposal;
67386
66838
  return result.turns;
67387
66839
  };
67388
- if (action.kind === "operation-progress" || action.kind === "task-proposal") {
66840
+ if (action.kind === "operation-progress") {
67389
66841
  const preview = applyHistoryAction(writer.readStored(), action);
67390
66842
  if (!preview.matched) return {
67391
- matched: false,
67392
- proposal: preview.proposal
66843
+ matched: false
67393
66844
  };
67394
66845
  }
67395
66846
  const target = historyActionTarget(action);
@@ -67398,8 +66849,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
67398
66849
  ])[0] ?? entry);
67399
66850
  else writer.update(apply);
67400
66851
  return {
67401
- matched,
67402
- proposal
66852
+ matched
67403
66853
  };
67404
66854
  },
67405
66855
  async appendTurn(turn) {
@@ -67425,17 +66875,6 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
67425
66875
  ]);
67426
66876
  commit();
67427
66877
  },
67428
- async resolveTaskProposal(entryId, proposalId, resolution) {
67429
- parseTaskProposalResolution(resolution);
67430
- let found = false;
67431
- writer.updateEntry(entryId, (entry) => {
67432
- if (!hasTaskProposal(entry, proposalId)) return entry;
67433
- resolveTaskProposalOnEntry(entry, proposalId, resolution);
67434
- found = true;
67435
- return entry;
67436
- });
67437
- return found;
67438
- },
67439
66878
  async respondPermission(requestId, outcome, respondOptions) {
67440
66879
  parseHistoryWrite(PermissionOutcomeSchema, outcome);
67441
66880
  return writer.respondPermission(requestId, outcome, respondOptions);
@@ -124140,7 +123579,6 @@ ${incoming}`).output;
124140
123579
  const MCP_HTTP_SESSION_ID_HEADER = "x-lody-mcp-session-id";
124141
123580
  const MCP_HTTP_WORKSPACE_ID_HEADER = "x-lody-mcp-workspace-id";
124142
123581
  const MCP_HTTP_MACHINE_ID_HEADER = "x-lody-mcp-machine-id";
124143
- const MCP_HTTP_TASK_TOOLS_ENABLED_HEADER = "x-lody-mcp-task-tools-enabled";
124144
123582
  const MCP_HTTP_WORKDIR_B64_HEADER = "x-lody-mcp-workdir-b64";
124145
123583
  const MCP_HTTP_TOKEN_ENV = "LODY_MCP_HTTP_TOKEN";
124146
123584
  const MCP_HTTP_PREFERRED_PORT_ENV = "LODY_MCP_HTTP_PREFERRED_PORT";
@@ -124165,10 +123603,6 @@ ${incoming}`).output;
124165
123603
  name: MCP_HTTP_MACHINE_ID_HEADER,
124166
123604
  value: context2.machineId
124167
123605
  },
124168
- {
124169
- name: MCP_HTTP_TASK_TOOLS_ENABLED_HEADER,
124170
- value: context2.taskToolsEnabled ? "1" : "0"
124171
- },
124172
123606
  {
124173
123607
  name: MCP_HTTP_WORKDIR_B64_HEADER,
124174
123608
  value: Buffer.from(context2.workdir, "utf8").toString("base64url")
@@ -130083,8 +129517,7 @@ ${incoming}`).output;
130083
129517
  sessionId: this.options.sessionId,
130084
129518
  workspaceId: this.options.workspaceId,
130085
129519
  machineId: this.options.machineId,
130086
- workdir,
130087
- taskToolsEnabled: this.options.taskToolsEnabled === true
129520
+ workdir
130088
129521
  })
130089
129522
  }
130090
129523
  ];
@@ -130114,10 +129547,6 @@ ${incoming}`).output;
130114
129547
  {
130115
129548
  name: "LODY_MCP_WORKDIR",
130116
129549
  value: workdir
130117
- },
130118
- {
130119
- name: "LODY_MCP_TASK_TOOLS_ENABLED",
130120
- value: this.options.taskToolsEnabled === true ? "1" : "0"
130121
129550
  }
130122
129551
  ];
130123
129552
  for (const [name2, value] of [
@@ -137047,7 +136476,6 @@ ${fallbackStderrTail}` : errorMessage2;
137047
136476
  agentConfig: options.agentConfig,
137048
136477
  configOptionValues: options.configOptionValues,
137049
136478
  resolveWorktreeProject: options.resolveWorktreeProject,
137050
- taskToolsEnabled: options.taskToolsEnabled,
137051
136479
  launcher: options.launcher,
137052
136480
  terminalEnabled: options.terminalEnabled,
137053
136481
  onStartupStage: options.onStartupStage,
@@ -145234,7 +144662,6 @@ ${withCauses}`;
145234
144662
  agentType: acpSessionConfig.agentType,
145235
144663
  configOptionValues: acpSessionConfig.configOptionValues,
145236
144664
  mcpServerIds: acpSessionConfig.mcpServerIds ?? [],
145237
- taskToolsEnabled: acpSessionConfig.taskToolsEnabled === true,
145238
144665
  customAcp: resumeCustomAcp,
145239
144666
  runtimeOverrides: resumeRuntimeOverrides,
145240
144667
  requesterUserId: userId,
@@ -145749,7 +145176,6 @@ ${withCauses}`;
145749
145176
  agentType: acpSessionConfig.agentType,
145750
145177
  configOptionValues: acpSessionConfig.configOptionValues,
145751
145178
  mcpServerIds: acpSessionConfig.mcpServerIds ?? [],
145752
- taskToolsEnabled: acpSessionConfig.taskToolsEnabled === true,
145753
145179
  agentConfigId: existingMeta?.agentConfigId,
145754
145180
  customAcp: acpSessionConfig.customAcp,
145755
145181
  runtimeOverrides: acpSessionConfig.runtimeOverrides,
@@ -148260,7 +147686,6 @@ ${withCauses}`;
148260
147686
  modelId: entry.inputConfig?.modelId,
148261
147687
  configOptionValues: entry.inputConfig?.configOptionValues,
148262
147688
  mcpServerIds: entry.inputConfig?.mcpServerIds ?? [],
148263
- taskToolsEnabled: entry.inputConfig?.taskToolsEnabled === true,
148264
147689
  agentRoleId: entry.inputConfig?.agentRoleId,
148265
147690
  agentRoleRevision: entry.inputConfig?.agentRoleRevision,
148266
147691
  issuePRMentions: entry.inputConfig?.issuePRMentions,
@@ -148295,7 +147720,6 @@ ${withCauses}`;
148295
147720
  modelId: entry.inputConfig?.modelId,
148296
147721
  configOptionValues: entry.inputConfig?.configOptionValues,
148297
147722
  mcpServerIds: entry.inputConfig?.mcpServerIds ?? [],
148298
- taskToolsEnabled: entry.inputConfig?.taskToolsEnabled === true,
148299
147723
  agentRoleId: entry.inputConfig?.agentRoleId,
148300
147724
  agentRoleRevision: entry.inputConfig?.agentRoleRevision,
148301
147725
  issuePRMentions: entry.inputConfig?.issuePRMentions,
@@ -148369,7 +147793,6 @@ ${withCauses}`;
148369
147793
  modelId: queuedItem.acpSessionConfig?.modelId,
148370
147794
  configOptionValues: isConfigOptionValueRecord(queuedItem.acpSessionConfig?.configOptionValues) ? queuedItem.acpSessionConfig.configOptionValues : void 0,
148371
147795
  mcpServerIds: normalizeMcpServerIdSelection(queuedItem.acpSessionConfig?.mcpServerIds) ?? [],
148372
- taskToolsEnabled: queuedItem.acpSessionConfig?.taskToolsEnabled === true,
148373
147796
  agentRoleId: queuedItem.acpSessionConfig?.agentRoleId,
148374
147797
  agentRoleRevision: queuedItem.acpSessionConfig?.agentRoleRevision,
148375
147798
  issuePRMentions: queuedItem.acpSessionConfig?.issuePRMentions,
@@ -149211,7 +148634,6 @@ ${withCauses}`;
149211
148634
  agentCliType: marker.cleanup.cliType,
149212
148635
  agentType: marker.cleanup.agentType,
149213
148636
  mcpServerIds: resolveSessionMcpSelection(history),
149214
- taskToolsEnabled: false,
149215
148637
  project: marker.cleanup.project,
149216
148638
  sessionId: targetSessionId,
149217
148639
  githubRepo: marker.cleanup.repoFullName,
@@ -149563,7 +148985,6 @@ ${withCauses}`;
149563
148985
  agentCliType: source.cliType,
149564
148986
  agentType: source.agentType,
149565
148987
  mcpServerIds: resolveSessionMcpSelection(historyResult.history),
149566
- taskToolsEnabled: resolveSessionTaskToolsEnabled(historyResult.history),
149567
148988
  customAcp: agentConfig.customAcp,
149568
148989
  runtimeOverrides: agentConfig.runtimeOverrides,
149569
148990
  env: agentConfig.env,
@@ -149657,7 +149078,6 @@ ${withCauses}`;
149657
149078
  agentCliType: source.cliType,
149658
149079
  agentType: source.agentType,
149659
149080
  mcpServerIds: resolveSessionMcpSelection(historyResult.history),
149660
- taskToolsEnabled: resolveSessionTaskToolsEnabled(historyResult.history),
149661
149081
  customAcp: agentConfig.customAcp,
149662
149082
  runtimeOverrides: agentConfig.runtimeOverrides,
149663
149083
  env: agentConfig.env,
@@ -149815,7 +149235,7 @@ ${withCauses}`;
149815
149235
  let commitEditable = editable;
149816
149236
  let commitMeta = meta;
149817
149237
  try {
149818
- runtime = await this.getOrRestoreRuntime(meta, spec.requestedByUserId, resolveSessionMcpSelection(history), spec.inputConfig.taskToolsEnabled === true);
149238
+ runtime = await this.getOrRestoreRuntime(meta, spec.requestedByUserId, resolveSessionMcpSelection(history));
149819
149239
  const agentClient = runtime.agentClient;
149820
149240
  oldAcpSessionId = runtime.acpSessionId;
149821
149241
  if (!agentClient || !oldAcpSessionId) {
@@ -150006,7 +149426,7 @@ ${withCauses}`;
150006
149426
  resume: preparedSessionId
150007
149427
  };
150008
149428
  }
150009
- async getOrRestoreRuntime(meta, requestedByUserId, mcpServerIds, taskToolsEnabled) {
149429
+ async getOrRestoreRuntime(meta, requestedByUserId, mcpServerIds) {
150010
149430
  const existing = this.deps.sessionManager.getSession(meta.id);
150011
149431
  if (existing) return existing;
150012
149432
  if (!meta.acpSessionId || !meta.agentConfigId) {
@@ -150027,7 +149447,6 @@ ${withCauses}`;
150027
149447
  agentCliType: meta.cliType,
150028
149448
  agentType: meta.agentType,
150029
149449
  mcpServerIds,
150030
- taskToolsEnabled,
150031
149450
  customAcp: agentConfig.customAcp,
150032
149451
  runtimeOverrides: agentConfig.runtimeOverrides,
150033
149452
  env: agentConfig.env,
@@ -150080,9 +149499,8 @@ ${withCauses}`;
150080
149499
  string$1(),
150081
149500
  boolean()
150082
149501
  ])).optional(),
150083
- taskToolsEnabled: boolean().optional(),
150084
149502
  inheritSessionDefaults: literal$1(false).optional()
150085
- }).strict().nullable()).optional()
149503
+ }).strip().nullable()).optional()
150086
149504
  }).strict();
150087
149505
  const OperationRowSchema = object$1({
150088
149506
  workspace_id: string$1(),
@@ -162757,510 +162175,6 @@ ${part.truncated ? TRUNCATION_MARKER : ""}${part.content}`).join("\n\n");
162757
162175
  }
162758
162176
  return table2.toString();
162759
162177
  }
162760
- const randomId = () => globalThis.crypto?.randomUUID?.() ?? `t${getServerNow()}${Math.floor(Math.random() * 1e6)}`;
162761
- const emptyTaskDocState = (taskId) => ({
162762
- meta: {
162763
- taskId,
162764
- title: "",
162765
- status: "backlog",
162766
- ownerId: "",
162767
- order: TASK_ORDER_MIN_KEY,
162768
- priority: void 0,
162769
- labels: void 0,
162770
- agent: void 0,
162771
- projects: void 0,
162772
- lastRunConfig: void 0,
162773
- createdAt: 0,
162774
- updatedAt: 0,
162775
- createdBy: void 0
162776
- },
162777
- body: "",
162778
- links: [],
162779
- timeline: []
162780
- });
162781
- const withTaskMirror = async (manager, taskId, fn, options) => {
162782
- const roomId = getTaskRoomId(taskId);
162783
- await manager.syncDocOrThrow(roomId, {
162784
- reason: `task:${taskId}`
162785
- }).catch(() => void 0);
162786
- const handle = await manager.repo.openPersistedDoc(roomId);
162787
- const mirror = new Mirror({
162788
- doc: handle.doc,
162789
- schema: taskDocSchema,
162790
- ignoreUnknownProperties: true,
162791
- ...options?.seedEmptyDocument ? {
162792
- initialState: emptyTaskDocState(taskId)
162793
- } : {}
162794
- });
162795
- try {
162796
- return await fn({
162797
- mirror,
162798
- syncOnce: async () => {
162799
- await handle.syncOnce();
162800
- }
162801
- });
162802
- } finally {
162803
- mirror.dispose();
162804
- }
162805
- };
162806
- const planWorkspaceTaskEnumeration = (indexRows, metaTaskIds) => {
162807
- const visibleTaskIds = listVisibleTaskIndexRows(indexRows).map((row) => row.taskId);
162808
- const missingIndexTaskIds = [
162809
- ...new Set(metaTaskIds)
162810
- ].filter((taskId) => !Object.prototype.hasOwnProperty.call(indexRows, taskId));
162811
- return {
162812
- visibleTaskIds,
162813
- missingIndexTaskIds
162814
- };
162815
- };
162816
- const readTaskIndexRowMap = async (manager, workspaceId, options) => {
162817
- const handle = await manager.repo.openFlockDoc(getTaskIndexFlockDocId(workspaceId));
162818
- if (options?.sync) {
162819
- await handle.syncOnce().catch(() => void 0);
162820
- }
162821
- return readTaskIndexRows(handle.flock.scan({
162822
- prefix: getTaskIndexScanPrefix()
162823
- }));
162824
- };
162825
- const listWorkspaceTaskIds = async (manager, workspaceId) => {
162826
- const indexRows = await readTaskIndexRowMap(manager, workspaceId);
162827
- const metaTaskIds = (await listAliveRoomIds(manager, isTaskDocRoomId)).map(getTaskIdFromRoomId).filter((taskId) => taskId !== null);
162828
- const plan = planWorkspaceTaskEnumeration(indexRows, metaTaskIds);
162829
- const taskIds = new Set(plan.visibleTaskIds);
162830
- for (const taskId of plan.missingIndexTaskIds) {
162831
- const snapshot = await readTask(manager, taskId).catch(() => null);
162832
- if (!snapshot || snapshot.meta.taskId !== taskId) {
162833
- continue;
162834
- }
162835
- taskIds.add(taskId);
162836
- await republishIndexRow(manager, workspaceId, snapshot).catch(() => void 0);
162837
- }
162838
- return [
162839
- ...taskIds
162840
- ];
162841
- };
162842
- const readTask = async (manager, taskId) => withTaskMirror(manager, taskId, ({ mirror }) => {
162843
- const state2 = mirror.getState();
162844
- if (!state2.meta?.taskId) {
162845
- return null;
162846
- }
162847
- return {
162848
- meta: state2.meta,
162849
- body: state2.body ?? "",
162850
- links: state2.links ?? [],
162851
- timeline: state2.timeline ?? []
162852
- };
162853
- });
162854
- const selectTaskIndexRows = (rows, filter2) => {
162855
- const needle = filter2.titleContains?.trim().toLowerCase();
162856
- const statuses = filter2.status && filter2.status.length > 0 ? new Set(filter2.status) : null;
162857
- const matches = listVisibleTaskIndexRows(rows).filter((row) => {
162858
- if (statuses && !statuses.has(row.status)) {
162859
- return false;
162860
- }
162861
- if (filter2.ownerId !== void 0 && (row.ownerId ?? "") !== filter2.ownerId) {
162862
- return false;
162863
- }
162864
- if (filter2.hasAgent !== void 0 && Boolean(row.hasAgent) !== filter2.hasAgent) {
162865
- return false;
162866
- }
162867
- if (needle && !row.title.toLowerCase().includes(needle)) {
162868
- return false;
162869
- }
162870
- return true;
162871
- });
162872
- matches.sort((a, b) => a.updatedAt === b.updatedAt ? a.taskId.localeCompare(b.taskId) : b.updatedAt - a.updatedAt);
162873
- return {
162874
- rows: matches.slice(0, filter2.limit),
162875
- matched: matches.length
162876
- };
162877
- };
162878
- const listTasksFromIndex = async (manager, workspaceId, filter2) => selectTaskIndexRows(await readTaskIndexRowMap(manager, workspaceId, {
162879
- sync: true
162880
- }), filter2);
162881
- async function republishIndexRow(manager, workspaceId, snapshot) {
162882
- const flockDocId = getTaskIndexFlockDocId(workspaceId);
162883
- const handle = await manager.repo.openFlockDoc(flockDocId);
162884
- const key2 = taskIndexKeys.task(snapshot.meta.taskId);
162885
- const row = buildTaskIndexRow(snapshot.meta, countTaskLinks(snapshot.links), summarizeTaskMentions(snapshot.timeline));
162886
- const previous = parseTaskIndexRow([
162887
- ...handle.flock.scan({
162888
- prefix: [
162889
- ...key2
162890
- ]
162891
- })
162892
- ].find((entry) => entry.key.length === key2.length)?.value);
162893
- if (previous && JSON.stringify(previous) === JSON.stringify(row)) {
162894
- return;
162895
- }
162896
- handle.flock.set([
162897
- ...key2
162898
- ], row);
162899
- handle.flock.commit();
162900
- await manager.repo.flush();
162901
- await handle.syncOnce().catch(() => void 0);
162902
- }
162903
- const sameLabelSet = (next2, previous) => next2.length === previous.length && [
162904
- ...next2
162905
- ].sort().join("\0") === [
162906
- ...previous
162907
- ].sort().join("\0");
162908
- const sameProjectList = (next2, previous) => JSON.stringify(next2.map(normalizeProjectRefForDedup)) === JSON.stringify(previous.map(normalizeProjectRefForDedup));
162909
- const buildAgentActorFields = (actor) => ({
162910
- actorKind: "agent",
162911
- ...actor.agentConfigId ? {
162912
- actorId: actor.agentConfigId
162913
- } : {},
162914
- ...actor.name ? {
162915
- actorName: actor.name
162916
- } : {}
162917
- });
162918
- const createTaskFromAgent = async (manager, workspaceId, input2, actor, creatorUserId) => {
162919
- if (isEmptyTaskDraft(input2)) {
162920
- return null;
162921
- }
162922
- const taskId = randomId();
162923
- const indexRows = await readTaskIndexRowMap(manager, workspaceId, {
162924
- sync: true
162925
- });
162926
- const order = generateTaskOrderKeyAtEnd(listVisibleTaskIndexRows(indexRows).map((row) => row.order), Math.random);
162927
- const labels = normalizeTaskLabels(input2.labels ? [
162928
- ...input2.labels
162929
- ] : void 0);
162930
- const snapshot = await withTaskMirror(manager, taskId, async ({ mirror, syncOnce }) => {
162931
- mirror.setState((draft) => {
162932
- const state2 = draft;
162933
- const now2 = getServerNow();
162934
- Object.assign(state2.meta, {
162935
- taskId,
162936
- title: deriveTaskTitle(input2),
162937
- status: input2.status ?? "backlog",
162938
- ownerId: input2.ownerId ?? creatorUserId,
162939
- order,
162940
- ...input2.priority ? {
162941
- priority: input2.priority
162942
- } : {},
162943
- ...labels.length > 0 ? {
162944
- labels
162945
- } : {},
162946
- ...input2.projects && input2.projects.length > 0 ? {
162947
- projects: [
162948
- ...input2.projects
162949
- ]
162950
- } : {},
162951
- createdAt: now2,
162952
- updatedAt: now2,
162953
- createdBy: creatorUserId
162954
- });
162955
- state2.body = input2.body ?? "";
162956
- state2.timeline.push({
162957
- id: randomId(),
162958
- kind: "activity",
162959
- ...buildAgentActorFields(actor),
162960
- createdAt: now2,
162961
- activityType: "created"
162962
- });
162963
- });
162964
- await manager.repo.flush();
162965
- await syncOnce().catch(() => void 0);
162966
- const after2 = mirror.getState();
162967
- return {
162968
- meta: after2.meta,
162969
- body: after2.body ?? "",
162970
- links: after2.links ?? [],
162971
- timeline: after2.timeline ?? []
162972
- };
162973
- }, {
162974
- seedEmptyDocument: true
162975
- });
162976
- await republishIndexRow(manager, workspaceId, snapshot);
162977
- return snapshot;
162978
- };
162979
- const applyAgentTaskUpdate = async (manager, workspaceId, taskId, input2, actor) => {
162980
- const result = await withTaskMirror(manager, taskId, async ({ mirror, syncOnce }) => {
162981
- const before = mirror.getState();
162982
- if (!before.meta?.taskId) {
162983
- return null;
162984
- }
162985
- const previous = before.meta;
162986
- const previousStatus = previous.status;
162987
- const alreadyLinked = input2.pullRequest !== void 0 && (before.links ?? []).some((link2) => link2.url === input2.pullRequest?.url && link2.removedAt === void 0);
162988
- mirror.setState((draft) => {
162989
- const state2 = draft;
162990
- const now2 = getServerNow();
162991
- const activities = [];
162992
- const recordActivity = (activityType, activityData) => {
162993
- activities.push({
162994
- id: randomId(),
162995
- kind: "activity",
162996
- ...buildAgentActorFields(actor),
162997
- createdAt: now2,
162998
- activityType,
162999
- ...activityData ? {
163000
- activityData
163001
- } : {}
163002
- });
163003
- };
163004
- if (input2.status !== void 0 && input2.status !== previousStatus) {
163005
- state2.meta.status = input2.status;
163006
- recordActivity("status_changed", {
163007
- from: previousStatus,
163008
- to: input2.status
163009
- });
163010
- }
163011
- if (input2.title !== void 0 && input2.title !== previous.title) {
163012
- state2.meta.title = input2.title;
163013
- recordActivity("title_changed", {
163014
- from: previous.title,
163015
- to: input2.title
163016
- });
163017
- }
163018
- if (input2.ownerId !== void 0 && input2.ownerId !== (previous.ownerId ?? "")) {
163019
- state2.meta.ownerId = input2.ownerId;
163020
- recordActivity("owner_changed", input2.ownerId ? {
163021
- to: input2.ownerId
163022
- } : {});
163023
- }
163024
- if (input2.priority !== void 0) {
163025
- const next2 = input2.priority ?? void 0;
163026
- if (next2 !== previous.priority) {
163027
- if (next2 === void 0) {
163028
- delete state2.meta.priority;
163029
- } else {
163030
- state2.meta.priority = next2;
163031
- }
163032
- recordActivity("priority_changed", next2 ? {
163033
- to: next2
163034
- } : {});
163035
- }
163036
- }
163037
- if (input2.labels !== void 0) {
163038
- const next2 = normalizeTaskLabels([
163039
- ...input2.labels
163040
- ]);
163041
- if (!sameLabelSet(next2, previous.labels ?? [])) {
163042
- state2.meta.labels = next2;
163043
- recordActivity("labels_changed", next2.length > 0 ? {
163044
- to: next2.join(", ")
163045
- } : {});
163046
- }
163047
- }
163048
- if (input2.projects !== void 0) {
163049
- const next2 = [
163050
- ...input2.projects
163051
- ];
163052
- if (!sameProjectList(next2, previous.projects ?? [])) {
163053
- state2.meta.projects = next2;
163054
- recordActivity("projects_changed", {
163055
- count: String(next2.length)
163056
- });
163057
- }
163058
- }
163059
- if (input2.pullRequest && !alreadyLinked) {
163060
- state2.links.push({
163061
- id: randomId(),
163062
- kind: "pr",
163063
- provider: input2.pullRequest.provider,
163064
- url: input2.pullRequest.url,
163065
- originSessionId: input2.pullRequest.originSessionId,
163066
- ...buildAgentActorFields(actor),
163067
- linkedAt: now2
163068
- });
163069
- recordActivity("pr_linked", {
163070
- url: input2.pullRequest.url
163071
- });
163072
- }
163073
- if (activities.length > 0) {
163074
- state2.meta.updatedAt = now2;
163075
- state2.timeline.push(...activities);
163076
- }
163077
- });
163078
- await manager.repo.flush();
163079
- await syncOnce().catch(() => void 0);
163080
- const after2 = mirror.getState();
163081
- return {
163082
- meta: after2.meta,
163083
- body: after2.body ?? "",
163084
- links: after2.links ?? [],
163085
- timeline: after2.timeline ?? []
163086
- };
163087
- });
163088
- if (result) {
163089
- await republishIndexRow(manager, workspaceId, result);
163090
- }
163091
- return result;
163092
- };
163093
- const planTaskBodyEdit = (currentBody, edit) => {
163094
- let nextBody;
163095
- if (edit.oldString === "") {
163096
- nextBody = currentBody ? `${currentBody}
163097
-
163098
- ${edit.newString}` : edit.newString;
163099
- } else {
163100
- const first2 = currentBody.indexOf(edit.oldString);
163101
- if (first2 < 0) {
163102
- return {
163103
- ok: false,
163104
- code: "NO_MATCH",
163105
- body: currentBody
163106
- };
163107
- }
163108
- if (currentBody.indexOf(edit.oldString, first2 + edit.oldString.length) >= 0) {
163109
- const occurrences = currentBody.split(edit.oldString).length - 1;
163110
- return {
163111
- ok: false,
163112
- code: "AMBIGUOUS_MATCH",
163113
- occurrences
163114
- };
163115
- }
163116
- nextBody = currentBody.slice(0, first2) + edit.newString + currentBody.slice(first2 + edit.oldString.length);
163117
- }
163118
- const delta = nextBody.length - currentBody.length;
163119
- return {
163120
- ok: true,
163121
- nextBody,
163122
- added: delta > 0 ? delta : 0,
163123
- removed: delta < 0 ? -delta : 0
163124
- };
163125
- };
163126
- const applyAgentTaskBodyEdit = async (manager, workspaceId, taskId, edit, actor, originSessionId) => {
163127
- const result = await withTaskMirror(manager, taskId, async ({ mirror, syncOnce }) => {
163128
- const before = mirror.getState();
163129
- if (!before.meta?.taskId) {
163130
- return {
163131
- ok: false,
163132
- code: "TASK_NOT_FOUND"
163133
- };
163134
- }
163135
- const currentBody = before.body ?? "";
163136
- const plan = planTaskBodyEdit(currentBody, edit);
163137
- if (!plan.ok) {
163138
- return plan;
163139
- }
163140
- const { nextBody, added, removed } = plan;
163141
- mirror.setState((draft) => {
163142
- const state2 = draft;
163143
- const now2 = getServerNow();
163144
- state2.body = nextBody;
163145
- state2.meta.updatedAt = now2;
163146
- state2.timeline.push({
163147
- id: randomId(),
163148
- kind: "activity",
163149
- ...buildAgentActorFields(actor),
163150
- createdAt: now2,
163151
- activityType: "body_edited",
163152
- activityData: {
163153
- added: String(added),
163154
- removed: String(removed)
163155
- },
163156
- ...originSessionId ? {
163157
- originSessionId
163158
- } : {}
163159
- });
163160
- });
163161
- await manager.repo.flush();
163162
- await syncOnce().catch(() => void 0);
163163
- const after2 = mirror.getState();
163164
- return {
163165
- ok: true,
163166
- snapshot: {
163167
- meta: after2.meta,
163168
- body: after2.body ?? "",
163169
- links: after2.links ?? [],
163170
- timeline: after2.timeline ?? []
163171
- },
163172
- added,
163173
- removed
163174
- };
163175
- });
163176
- if (result.ok) {
163177
- await republishIndexRow(manager, workspaceId, result.snapshot);
163178
- }
163179
- return result;
163180
- };
163181
- const appendAgentTaskComment = async (manager, workspaceId, taskId, input2, actor) => {
163182
- const snapshot = await withTaskMirror(manager, taskId, async ({ mirror, syncOnce }) => {
163183
- const before = mirror.getState();
163184
- if (!before.meta?.taskId) {
163185
- return null;
163186
- }
163187
- mirror.setState((draft) => {
163188
- const state2 = draft;
163189
- state2.timeline.push({
163190
- id: randomId(),
163191
- kind: "comment",
163192
- ...buildAgentActorFields(actor),
163193
- createdAt: getServerNow(),
163194
- body: input2.body,
163195
- ...input2.mentions && input2.mentions.length > 0 ? {
163196
- mentions: input2.mentions
163197
- } : {},
163198
- ...input2.originSessionId ? {
163199
- originSessionId: input2.originSessionId
163200
- } : {}
163201
- });
163202
- state2.meta.updatedAt = getServerNow();
163203
- });
163204
- await manager.repo.flush();
163205
- await syncOnce().catch(() => void 0);
163206
- const after2 = mirror.getState();
163207
- return after2.meta?.taskId ? after2 : null;
163208
- });
163209
- if (!snapshot) {
163210
- return false;
163211
- }
163212
- await republishIndexRow(manager, workspaceId, snapshot);
163213
- return true;
163214
- };
163215
- const linkTaskSessionFromCli = async (manager, workspaceId, taskId, input2, actor) => {
163216
- const result = await withTaskMirror(manager, taskId, async ({ mirror, syncOnce }) => {
163217
- const before = mirror.getState();
163218
- if (!before.meta?.taskId) {
163219
- return null;
163220
- }
163221
- if ((before.links ?? []).some((link2) => link2.sessionId === input2.sessionId && link2.removedAt === void 0)) {
163222
- return null;
163223
- }
163224
- mirror.setState((draft) => {
163225
- const state2 = draft;
163226
- const now2 = getServerNow();
163227
- state2.links.push({
163228
- id: randomId(),
163229
- kind: "session",
163230
- sessionId: input2.sessionId,
163231
- origin: input2.origin,
163232
- ...input2.parentSessionId ? {
163233
- parentSessionId: input2.parentSessionId
163234
- } : {},
163235
- ...buildAgentActorFields(actor),
163236
- linkedAt: now2
163237
- });
163238
- state2.timeline.push({
163239
- id: randomId(),
163240
- kind: "activity",
163241
- ...buildAgentActorFields(actor),
163242
- createdAt: now2,
163243
- activityType: "session_linked",
163244
- activityData: {
163245
- origin: input2.origin
163246
- }
163247
- });
163248
- state2.meta.updatedAt = now2;
163249
- });
163250
- await manager.repo.flush();
163251
- await syncOnce().catch(() => void 0);
163252
- const after2 = mirror.getState();
163253
- return {
163254
- meta: after2.meta,
163255
- body: after2.body ?? "",
163256
- links: after2.links ?? [],
163257
- timeline: after2.timeline ?? []
163258
- };
163259
- });
163260
- if (result) {
163261
- await republishIndexRow(manager, workspaceId, result);
163262
- }
163263
- };
163264
162178
  function sortAgentConfigs(configs) {
163265
162179
  return [
163266
162180
  ...configs
@@ -164727,7 +163641,6 @@ ${entry.text}`).join("\n\n");
164727
163641
  modeId: args2.modeId,
164728
163642
  modelId: args2.modelId,
164729
163643
  configOptionValues: args2.configOptionValues && Object.keys(args2.configOptionValues).length > 0 ? args2.configOptionValues : void 0,
164730
- taskToolsEnabled: args2.taskToolsEnabled === true,
164731
163644
  resume: args2.resume,
164732
163645
  chainDepth: args2.chainDepth
164733
163646
  };
@@ -164748,9 +163661,6 @@ ${entry.text}`).join("\n\n");
164748
163661
  };
164749
163662
  return {
164750
163663
  config: {
164751
- ...rest.taskToolsEnabled !== void 0 ? {
164752
- taskToolsEnabled: rest.taskToolsEnabled
164753
- } : {},
164754
163664
  ...resolved.modeId ?? rest.modeId ? {
164755
163665
  modeId: resolved.modeId ?? rest.modeId
164756
163666
  } : {},
@@ -164827,8 +163737,7 @@ ${entry.text}`).join("\n\n");
164827
163737
  return {
164828
163738
  modeId: explicitConfig.modeId ?? fallbackConfig?.modeId,
164829
163739
  modelId: explicitConfig.modelId ?? fallbackConfig?.modelId,
164830
- configOptionValues: explicitConfig.configOptionValues ?? fallbackConfig?.configOptionValues,
164831
- taskToolsEnabled: explicitConfig.taskToolsEnabled ?? fallbackConfig?.taskToolsEnabled
163740
+ configOptionValues: explicitConfig.configOptionValues ?? fallbackConfig?.configOptionValues
164832
163741
  };
164833
163742
  }
164834
163743
  function validateConfigOptionValue(option2, value) {
@@ -164963,9 +163872,6 @@ ${entry.text}`).join("\n\n");
164963
163872
  } : {},
164964
163873
  ...configOptionValues ? {
164965
163874
  configOptionValues
164966
- } : {},
164967
- ...config2.taskToolsEnabled !== void 0 ? {
164968
- taskToolsEnabled: config2.taskToolsEnabled
164969
163875
  } : {}
164970
163876
  };
164971
163877
  }
@@ -164997,9 +163903,6 @@ ${entry.text}`).join("\n\n");
164997
163903
  } : {},
164998
163904
  ...inputConfig.configOptionValues ? {
164999
163905
  configOptionValues: inputConfig.configOptionValues
165000
- } : {},
165001
- ...inputConfig.taskToolsEnabled !== void 0 ? {
165002
- taskToolsEnabled: inputConfig.taskToolsEnabled
165003
163906
  } : {}
165004
163907
  };
165005
163908
  }
@@ -165703,7 +164606,6 @@ ${entry.text}`).join("\n\n");
165703
164606
  const currentSession = currentSessionId ? await resolveSessionMetaOrThrow(args2.manager, currentSessionId) : void 0;
165704
164607
  const parentSession = parentSessionId ? await resolveSessionMetaOrThrow(args2.manager, parentSessionId) : void 0;
165705
164608
  assertSupportedParentDepth(parentSession);
165706
- const taskId = normalizeCliValue(args2.options.taskId) ?? currentSession?.taskId;
165707
164609
  const targetMachine = await resolveTargetMachineForCreate({
165708
164610
  manager: args2.manager,
165709
164611
  workspaceId,
@@ -165789,10 +164691,7 @@ ${entry.text}`).join("\n\n");
165789
164691
  ...parentSessionId ? {
165790
164692
  parentSessionId
165791
164693
  } : {},
165792
- ...resolveOpenedBySessionRelation(currentSession),
165793
- ...taskId ? {
165794
- taskId
165795
- } : {}
164694
+ ...resolveOpenedBySessionRelation(currentSession)
165796
164695
  };
165797
164696
  }
165798
164697
  async function validateSessionCreateOptions(args2) {
@@ -165866,7 +164765,7 @@ ${entry.text}`).join("\n\n");
165866
164765
  options,
165867
164766
  requester
165868
164767
  });
165869
- const { targetMachine, agentConfig, project, parentSessionId, openedBySessionId, openedByRootSessionId, taskId } = resolved;
164768
+ const { targetMachine, agentConfig, project, parentSessionId, openedBySessionId, openedByRootSessionId } = resolved;
165870
164769
  const effectiveDispatchConfig = await resolveEffectiveSessionCreateDispatchConfig({
165871
164770
  manager,
165872
164771
  workspaceId: workspace.id,
@@ -165918,9 +164817,6 @@ ${entry.text}`).join("\n\n");
165918
164817
  } : {},
165919
164818
  ...options.agentRoleRevision !== void 0 ? {
165920
164819
  agentRoleRevision: options.agentRoleRevision
165921
- } : {},
165922
- ...taskId ? {
165923
- taskId
165924
164820
  } : {}
165925
164821
  });
165926
164822
  let completionAbortController;
@@ -165941,7 +164837,6 @@ ${entry.text}`).join("\n\n");
165941
164837
  modeId: modeId ?? void 0,
165942
164838
  modelId: modelId ?? void 0,
165943
164839
  configOptionValues: effectiveDispatchConfig.configOptionValues,
165944
- taskToolsEnabled: taskId ? true : effectiveDispatchConfig.taskToolsEnabled,
165945
164840
  chainDepth: options.chainDepth
165946
164841
  }),
165947
164842
  preallocatedId: options.userTurnId
@@ -165981,17 +164876,6 @@ ${entry.text}`).join("\n\n");
165981
164876
  timestamp: userTurn.timestamp,
165982
164877
  inputConfig: userTurn.inputConfig
165983
164878
  });
165984
- if (taskId) {
165985
- await linkTaskSessionFromCli(manager, workspace.id, taskId, {
165986
- sessionId,
165987
- origin: options.taskLinkOrigin ?? "agent-spawn",
165988
- ...openedBySessionId ? {
165989
- parentSessionId: openedBySessionId
165990
- } : {}
165991
- }, {
165992
- agentConfigId: agentConfig.id
165993
- }).catch(() => void 0);
165994
- }
165995
164879
  return {
165996
164880
  sessionId,
165997
164881
  machineId: targetMachine.id,
@@ -166010,9 +164894,6 @@ ${entry.text}`).join("\n\n");
166010
164894
  ...openedByRootSessionId ? {
166011
164895
  openedByRootSessionId
166012
164896
  } : {},
166013
- ...taskId ? {
166014
- taskId
166015
- } : {},
166016
164897
  completionPromise
166017
164898
  };
166018
164899
  } catch (error2) {
@@ -166098,7 +164979,6 @@ ${entry.text}`).join("\n\n");
166098
164979
  modeId: effectiveDispatchConfig.modeId,
166099
164980
  modelId: effectiveDispatchConfig.modelId,
166100
164981
  configOptionValues: effectiveDispatchConfig.configOptionValues,
166101
- taskToolsEnabled: effectiveDispatchConfig.taskToolsEnabled,
166102
164982
  resume: session2.acpSessionId ?? void 0,
166103
164983
  chainDepth: orchestration?.chainDepth
166104
164984
  }),
@@ -173701,7 +172581,7 @@ ${entry.text}`).join("\n\n");
173701
172581
  const shouldIgnoreTunnelSendError = (error2) => options.interrupted() || error2 instanceof Error && error2.message === "Tunnel connection is unavailable";
173702
172582
  const handleBackgroundTunnelSendError = (error2) => {
173703
172583
  if (!shouldIgnoreTunnelSendError(error2)) {
173704
- console.warn(`Failed to send preview tunnel message: ${formatError$1(error2)}`);
172584
+ console.warn(`Failed to send preview tunnel message: ${formatError(error2)}`);
173705
172585
  }
173706
172586
  };
173707
172587
  return new Promise((resolve2, reject2) => {
@@ -173745,7 +172625,7 @@ ${entry.text}`).join("\n\n");
173745
172625
  });
173746
172626
  return;
173747
172627
  }
173748
- const message = event.message || formatError$1(event.error) || "Unknown WebSocket error";
172628
+ const message = event.message || formatError(event.error) || "Unknown WebSocket error";
173749
172629
  resolve2({
173750
172630
  kind: "disconnected",
173751
172631
  message: `Preview tunnel connection error: ${message}`
@@ -173809,7 +172689,7 @@ ${entry.text}`).join("\n\n");
173809
172689
  void sendMessage({
173810
172690
  type: "response-error",
173811
172691
  requestId: message.requestId,
173812
- message: formatError$1(error2)
172692
+ message: formatError(error2)
173813
172693
  }).catch(handleBackgroundTunnelSendError);
173814
172694
  });
173815
172695
  return;
@@ -173836,7 +172716,7 @@ ${entry.text}`).join("\n\n");
173836
172716
  void sendMessage({
173837
172717
  type: "websocket-reject",
173838
172718
  requestId: message.requestId,
173839
- message: formatError$1(error2)
172719
+ message: formatError(error2)
173840
172720
  }).catch(handleBackgroundTunnelSendError);
173841
172721
  }
173842
172722
  return;
@@ -174021,7 +172901,7 @@ ${entry.text}`).join("\n\n");
174021
172901
  await sendMessage({
174022
172902
  type: "response-error",
174023
172903
  requestId: message.requestId,
174024
- message: formatError$1(error2)
172904
+ message: formatError(error2)
174025
172905
  }).catch((sendError) => {
174026
172906
  if (!shouldIgnoreTunnelSendError(sendError)) throw sendError;
174027
172907
  });
@@ -174094,7 +172974,7 @@ ${entry.text}`).join("\n\n");
174094
172974
  localSocket.terminate();
174095
172975
  });
174096
172976
  localSocket.on("error", (error2) => {
174097
- if (!socketContext.handshakeSettled) rejectHandshake(formatError$1(error2));
172977
+ if (!socketContext.handshakeSettled) rejectHandshake(formatError(error2));
174098
172978
  });
174099
172979
  localSocket.on("close", (code2, reasonBuffer) => {
174100
172980
  const reason = Buffer$2.from(reasonBuffer).toString("utf8");
@@ -174185,7 +173065,7 @@ ${entry.text}`).join("\n\n");
174185
173065
  queueBackgroundMessage({
174186
173066
  type: "response-error",
174187
173067
  requestId,
174188
- message: formatError$1(error2)
173068
+ message: formatError(error2)
174189
173069
  });
174190
173070
  }
174191
173071
  });
@@ -174515,12 +173395,12 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
174515
173395
  function formatLocalWebSocketClose(code2, reason) {
174516
173396
  return reason ? `Local WebSocket connection closed during handshake (${code2}: ${reason})` : `Local WebSocket connection closed during handshake (${code2})`;
174517
173397
  }
174518
- function formatError$1(error2) {
173398
+ function formatError(error2) {
174519
173399
  if (error2 instanceof Error) return error2.message;
174520
173400
  return typeof error2 === "string" ? error2 : "Unknown error";
174521
173401
  }
174522
173402
  function asError(error2) {
174523
- return error2 instanceof Error ? error2 : new Error(formatError$1(error2));
173403
+ return error2 instanceof Error ? error2 : new Error(formatError(error2));
174524
173404
  }
174525
173405
  async function withTimeout$1(promise2, timeoutMs, message) {
174526
173406
  let timeoutHandle;
@@ -179544,10 +178424,7 @@ ${escapeHtmlScriptContent(VISUAL_ANNOTATION_INSPECTOR_BROWSER_SCRIPT)}
179544
178424
  await createSessionResult(auth, workspace, this.workspaceDocument, prompt2, options, dispatchConfig);
179545
178425
  return;
179546
178426
  }
179547
- await sendSessionChatResult(auth, workspace, this.workspaceDocument, item.target.sessionId, prompt2, {
179548
- ...resolveTurnDispatchConfig({}),
179549
- taskToolsEnabled: operation.frozenContinuationConfig.inputConfig.taskToolsEnabled === true
179550
- }, void 0, delegatedRequester ? void 0 : operation.requesterUserId, {
178427
+ await sendSessionChatResult(auth, workspace, this.workspaceDocument, item.target.sessionId, prompt2, resolveTurnDispatchConfig({}), void 0, delegatedRequester ? void 0 : operation.requesterUserId, {
179551
178428
  userTurnId: item.target.userTurnId,
179552
178429
  chainDepth: operation.initiatorChainDepth + 1,
179553
178430
  bypassSessionQuota: shouldBypassSessionQuota(operation.kind)
@@ -188416,7 +187293,6 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
188416
187293
  agentType: callbacks.agentType
188417
187294
  },
188418
187295
  configOptionValues: this.config.configOptionValues,
188419
- taskToolsEnabled: this.config.taskToolsEnabled,
188420
187296
  launcher,
188421
187297
  workspaceId: this.config.workspaceId,
188422
187298
  machineId: this.config.machineId,
@@ -189154,7 +188030,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189154
188030
  }
189155
188031
  };
189156
188032
  }
189157
- function buildSessionPreparationCompatibility(launchSource, mcpServerIds, configOptionValues, taskToolsEnabled) {
188033
+ function buildSessionPreparationCompatibility(launchSource, mcpServerIds, configOptionValues) {
189158
188034
  return {
189159
188035
  launch: buildSessionLaunchConfig({
189160
188036
  customAcp: launchSource?.customAcp,
@@ -189165,8 +188041,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189165
188041
  mcpServerIds: mcpServerIds ? [
189166
188042
  ...mcpServerIds
189167
188043
  ] : void 0,
189168
- configOptionValues,
189169
- taskToolsEnabled
188044
+ configOptionValues
189170
188045
  })
189171
188046
  };
189172
188047
  }
@@ -189283,7 +188158,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189283
188158
  return null;
189284
188159
  }
189285
188160
  const current2 = resource.readCurrentLaunchConfig(sessionMeta);
189286
- if (!current2 || !isDeepStrictEqual(resource.compatibility, buildSessionPreparationCompatibility(current2.config, resource.config.mcpServerIds, resource.config.configOptionValues, resource.config.taskToolsEnabled))) {
188161
+ if (!current2 || !isDeepStrictEqual(resource.compatibility, buildSessionPreparationCompatibility(current2.config, resource.config.mcpServerIds, resource.config.configOptionValues))) {
189287
188162
  return null;
189288
188163
  }
189289
188164
  return {
@@ -189324,7 +188199,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189324
188199
  await this.preparationService.discard(sessionId);
189325
188200
  return await this.createSessionInnerWithAgent(config2, agentStart);
189326
188201
  }
189327
- const compatibility = buildSessionPreparationCompatibility(config2, config2.mcpServerIds, config2.configOptionValues, config2.taskToolsEnabled);
188202
+ const compatibility = buildSessionPreparationCompatibility(config2, config2.mcpServerIds, config2.configOptionValues);
189328
188203
  const claim = this.preparationService.claim({
189329
188204
  sessionId,
189330
188205
  requesterUserId: config2.requesterUserId,
@@ -189343,7 +188218,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189343
188218
  cliType: config2.agentCliType,
189344
188219
  agentType: config2.agentType
189345
188220
  });
189346
- return current2 !== null && isDeepStrictEqual(resource.compatibility, buildSessionPreparationCompatibility(current2.config, config2.mcpServerIds, config2.configOptionValues, config2.taskToolsEnabled));
188221
+ return current2 !== null && isDeepStrictEqual(resource.compatibility, buildSessionPreparationCompatibility(current2.config, config2.mcpServerIds, config2.configOptionValues));
189347
188222
  }
189348
188223
  });
189349
188224
  if (claim.status === "miss") {
@@ -189501,7 +188376,6 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189501
188376
  agentType: spec.agentType,
189502
188377
  configOptionValues: spec.runConfig?.configOptionValues,
189503
188378
  mcpServerIds: spec.runConfig?.mcpServerIds ?? [],
189504
- taskToolsEnabled: spec.runConfig?.taskToolsEnabled === true,
189505
188379
  customAcp: agentConfig.customAcp,
189506
188380
  runtimeOverrides: agentConfig.runtimeOverrides,
189507
188381
  project: spec.project,
@@ -189515,7 +188389,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
189515
188389
  userName: user.name,
189516
188390
  userEmail: user.email
189517
188391
  };
189518
- const compatibility = buildSessionPreparationCompatibility(config2, config2.mcpServerIds, config2.configOptionValues, config2.taskToolsEnabled);
188392
+ const compatibility = buildSessionPreparationCompatibility(config2, config2.mcpServerIds, config2.configOptionValues);
189519
188393
  const ghTokenInjected = await this.prepareGitHubRepoSessionConfig(config2);
189520
188394
  signal.throwIfAborted();
189521
188395
  const launch = await resolveACPProcessLaunchAsync({
@@ -194426,344 +193300,6 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
194426
193300
  counters: () => scheduler.counters
194427
193301
  };
194428
193302
  };
194429
- const isTaskAutomationEligible = (candidate, input2) => {
194430
- const agentConfigId = candidate.agentConfigId;
194431
- if (!agentConfigId) {
194432
- return false;
194433
- }
194434
- if (candidate.status !== "backlog" && candidate.status !== "todo") {
194435
- return false;
194436
- }
194437
- if (!candidate.ready) {
194438
- return false;
194439
- }
194440
- if (!input2.ownedAgentConfigIds.has(agentConfigId)) {
194441
- return false;
194442
- }
194443
- return candidate.ownerId === input2.operatorUserId;
194444
- };
194445
- const planTaskAutomation = (input2) => {
194446
- const plan = {
194447
- start: [],
194448
- queued: [],
194449
- waitingForAgent: [],
194450
- skippedAsBaseline: []
194451
- };
194452
- const busyAgentConfigIds = new Set(input2.inFlightByAgentConfigId.keys());
194453
- for (const candidate of input2.candidates) {
194454
- if (candidate.agentConfigId && candidate.status === "in_progress" && candidate.ownerId === input2.operatorUserId) {
194455
- busyAgentConfigIds.add(candidate.agentConfigId);
194456
- }
194457
- }
194458
- const byAgent = /* @__PURE__ */ new Map();
194459
- for (const candidate of input2.candidates) {
194460
- if (!isTaskAutomationEligible(candidate, input2)) {
194461
- continue;
194462
- }
194463
- if (input2.startedTaskIds.has(candidate.taskId)) {
194464
- continue;
194465
- }
194466
- if (input2.baselineTaskIds.has(candidate.taskId)) {
194467
- plan.skippedAsBaseline.push(candidate.taskId);
194468
- continue;
194469
- }
194470
- const agentConfigId = candidate.agentConfigId;
194471
- const bucket = byAgent.get(agentConfigId);
194472
- if (bucket) {
194473
- bucket.push(candidate);
194474
- } else {
194475
- byAgent.set(agentConfigId, [
194476
- candidate
194477
- ]);
194478
- }
194479
- }
194480
- for (const [agentConfigId, bucket] of byAgent) {
194481
- const ordered = [
194482
- ...bucket
194483
- ].sort((a, b) => compareTaskOrder({
194484
- order: a.order,
194485
- id: a.taskId
194486
- }, {
194487
- order: b.order,
194488
- id: b.taskId
194489
- }));
194490
- if (!input2.onlineAgentConfigIds.has(agentConfigId)) {
194491
- for (const candidate of ordered) {
194492
- plan.waitingForAgent.push({
194493
- taskId: candidate.taskId,
194494
- agentConfigId
194495
- });
194496
- }
194497
- continue;
194498
- }
194499
- const busy = busyAgentConfigIds.has(agentConfigId);
194500
- let position = 0;
194501
- for (const [index, candidate] of ordered.entries()) {
194502
- if (!busy && index === 0) {
194503
- plan.start.push({
194504
- taskId: candidate.taskId,
194505
- agentConfigId
194506
- });
194507
- continue;
194508
- }
194509
- position += 1;
194510
- plan.queued.push({
194511
- taskId: candidate.taskId,
194512
- agentConfigId,
194513
- position
194514
- });
194515
- }
194516
- }
194517
- return plan;
194518
- };
194519
- const collectTaskAutomationBaseline = (candidates, input2) => {
194520
- const baseline = /* @__PURE__ */ new Set();
194521
- for (const candidate of candidates) {
194522
- if (isTaskAutomationEligible(candidate, input2)) {
194523
- baseline.add(candidate.taskId);
194524
- }
194525
- }
194526
- return baseline;
194527
- };
194528
- const toCandidate = (row) => ({
194529
- taskId: row.taskId,
194530
- order: row.order,
194531
- ownerId: row.ownerId,
194532
- ...row.agentConfigId ? {
194533
- agentConfigId: row.agentConfigId
194534
- } : {},
194535
- status: row.status,
194536
- ready: row.ready !== false
194537
- });
194538
- class TaskAutomationScheduler {
194539
- deps;
194540
- baseline = null;
194541
- started = /* @__PURE__ */ new Set();
194542
- inFlightByAgentConfigId = /* @__PURE__ */ new Map();
194543
- running = false;
194544
- rerunRequested = false;
194545
- stopped = false;
194546
- constructor(deps) {
194547
- this.deps = deps;
194548
- }
194549
- stop() {
194550
- this.stopped = true;
194551
- }
194552
- async evaluate() {
194553
- if (this.stopped) {
194554
- return;
194555
- }
194556
- if (this.running) {
194557
- this.rerunRequested = true;
194558
- return;
194559
- }
194560
- this.running = true;
194561
- try {
194562
- do {
194563
- this.rerunRequested = false;
194564
- await this.runPass();
194565
- } while (this.rerunRequested && !this.stopped);
194566
- } finally {
194567
- this.running = false;
194568
- }
194569
- }
194570
- async runPass() {
194571
- const rows = await this.deps.readTaskIndex();
194572
- const candidates = rows.map(toCandidate);
194573
- const ownedAgents = await this.deps.listOwnedAgentConfigs();
194574
- const ownedAgentConfigIds = new Set(ownedAgents.filter((config2) => config2.machineId === this.deps.machineId).map((config2) => config2.id));
194575
- if (this.baseline === null) {
194576
- this.baseline = collectTaskAutomationBaseline(candidates, {
194577
- ownedAgentConfigIds,
194578
- operatorUserId: this.deps.operatorUserId
194579
- });
194580
- if (this.baseline.size > 0) {
194581
- this.deps.logger.debug(`[task-automation] baseline recorded count=${this.baseline.size} (not started)`);
194582
- }
194583
- return;
194584
- }
194585
- const stillEligible = new Set(candidates.filter((entry) => (entry.status === "backlog" || entry.status === "todo") && entry.ready && entry.agentConfigId).map((entry) => entry.taskId));
194586
- for (const taskId of [
194587
- ...this.baseline
194588
- ]) {
194589
- if (!stillEligible.has(taskId)) {
194590
- this.baseline.delete(taskId);
194591
- }
194592
- }
194593
- const onlineAgentConfigIds = this.deps.isMachineOnline() ? ownedAgentConfigIds : /* @__PURE__ */ new Set();
194594
- const plan = planTaskAutomation({
194595
- candidates,
194596
- ownedAgentConfigIds,
194597
- onlineAgentConfigIds,
194598
- operatorUserId: this.deps.operatorUserId,
194599
- inFlightByAgentConfigId: this.inFlightByAgentConfigId,
194600
- baselineTaskIds: this.baseline,
194601
- startedTaskIds: this.started
194602
- });
194603
- for (const queued of plan.queued) {
194604
- this.deps.onQueued?.(queued.taskId, queued.position);
194605
- }
194606
- for (const start2 of plan.start) {
194607
- if (this.inFlightByAgentConfigId.has(start2.agentConfigId)) {
194608
- continue;
194609
- }
194610
- this.inFlightByAgentConfigId.set(start2.agentConfigId, start2.taskId);
194611
- this.started.add(start2.taskId);
194612
- try {
194613
- this.deps.logger.debug(`[task-automation] starting taskId=${start2.taskId} agentConfigId=${start2.agentConfigId}`);
194614
- await this.deps.startTask(start2.taskId, start2.agentConfigId);
194615
- } catch (error2) {
194616
- this.started.delete(start2.taskId);
194617
- this.deps.logger.warn(`[task-automation] failed to start taskId=${start2.taskId}: ${error2 instanceof Error ? error2.message : String(error2)}`);
194618
- } finally {
194619
- this.inFlightByAgentConfigId.delete(start2.agentConfigId);
194620
- }
194621
- }
194622
- }
194623
- }
194624
- const readTaskIndexRowsForWorkspace = async (repo, workspaceId) => {
194625
- const handle = await repo.openFlockDoc(getTaskIndexFlockDocId(workspaceId));
194626
- return listVisibleTaskIndexRows(readTaskIndexRows(handle.flock.scan({
194627
- prefix: getTaskIndexScanPrefix()
194628
- })));
194629
- };
194630
- function createTaskAutomationWorkspace(options) {
194631
- const { documentManager, workspaceId, machineId, userId, logger: logger2, startTask } = options;
194632
- const flockDocId = getTaskIndexFlockDocId(workspaceId);
194633
- const readTaskIndex = () => readTaskIndexRowsForWorkspace(documentManager.repo, workspaceId);
194634
- const scheduler = new TaskAutomationScheduler({
194635
- workspaceId,
194636
- machineId,
194637
- operatorUserId: userId,
194638
- logger: logger2,
194639
- readTaskIndex,
194640
- listOwnedAgentConfigs: () => listMergedAgentConfigs(documentManager.repo, workspaceId, [
194641
- machineId
194642
- ]).catch(() => []),
194643
- isMachineOnline: () => documentManager.isTransportConnected(),
194644
- startTask,
194645
- onQueued: (taskId, position) => {
194646
- logger2.debug(`[task-automation] queued taskId=${taskId} position=${position}`);
194647
- }
194648
- });
194649
- let unsubscribe = null;
194650
- let disposed = false;
194651
- let joined = null;
194652
- const detachReconnect = documentManager.onStreamsOnline(() => {
194653
- if (disposed) {
194654
- return;
194655
- }
194656
- void scheduler.evaluate().catch(() => void 0);
194657
- });
194658
- void (async () => {
194659
- try {
194660
- const handle = await documentManager.repo.openFlockDoc(flockDocId);
194661
- if (disposed) {
194662
- return;
194663
- }
194664
- await scheduler.evaluate();
194665
- unsubscribe = handle.flock.subscribe(() => {
194666
- if (disposed) {
194667
- return;
194668
- }
194669
- void scheduler.evaluate().catch(() => void 0);
194670
- });
194671
- const subscription = await handle.joinRoom();
194672
- if (disposed) {
194673
- subscription.unsubscribe();
194674
- return;
194675
- }
194676
- joined = subscription;
194677
- await streamsRoomBinding(subscription).firstSyncedWithRemote;
194678
- if (!disposed) {
194679
- await scheduler.evaluate();
194680
- }
194681
- } catch (error2) {
194682
- if (!disposed) {
194683
- logger2.warn(`[task-automation] failed to attach task index: ${error2 instanceof Error ? error2.message : String(error2)}`);
194684
- }
194685
- }
194686
- })();
194687
- return {
194688
- evaluate: () => scheduler.evaluate(),
194689
- dispose: async () => {
194690
- disposed = true;
194691
- scheduler.stop();
194692
- detachReconnect();
194693
- unsubscribe?.();
194694
- joined?.unsubscribe();
194695
- }
194696
- };
194697
- }
194698
- const buildAutomationBrief = (title2, body2) => {
194699
- const trimmed2 = body2.trim();
194700
- const header = `You are executing a Lody task that was delegated to you.
194701
-
194702
- Task: ${title2}`;
194703
- const closing = "\n\nWhen you finish, call lody_task_update to move the task to needs_review (and link the pull request if you opened one), and lody_task_comment to summarize what you did. Nobody is watching this session, so that report is how the work becomes visible.";
194704
- if (!trimmed2) {
194705
- return `${header}
194706
-
194707
- (The task has no description. If the title is not enough to act on, say so in a task comment instead of guessing.)${closing}`;
194708
- }
194709
- return `${header}
194710
-
194711
- ---
194712
-
194713
- ${trimmed2}${closing}`;
194714
- };
194715
- const buildProjectOptions = (project) => {
194716
- if (!project) {
194717
- return {};
194718
- }
194719
- if (project.kind === "github") {
194720
- return {
194721
- repo: project.repoFullName,
194722
- ...project.branch ? {
194723
- branch: project.branch
194724
- } : {}
194725
- };
194726
- }
194727
- return {
194728
- localProject: project.localProjectId,
194729
- ...project.branch ? {
194730
- branch: project.branch
194731
- } : {},
194732
- ...project.useWorktree ? {
194733
- worktree: true
194734
- } : {}
194735
- };
194736
- };
194737
- const startDelegatedTask = async (deps, taskId, agentConfigId) => {
194738
- const snapshot = await readTask(deps.manager, taskId);
194739
- if (!snapshot) {
194740
- throw new Error(`Task not found: ${taskId}`);
194741
- }
194742
- const projects = snapshot.meta.projects ?? [];
194743
- const project = projects[0];
194744
- if (!project) {
194745
- throw new Error(`Task has no project: ${taskId}`);
194746
- }
194747
- const result = await deps.createSession({
194748
- auth: deps.auth,
194749
- workspace: deps.workspace,
194750
- manager: deps.manager,
194751
- prompt: buildAutomationBrief(snapshot.meta.title, snapshot.body),
194752
- options: {
194753
- agentConfig: agentConfigId,
194754
- taskId,
194755
- taskLinkOrigin: "run",
194756
- title: snapshot.meta.title.slice(0, 50),
194757
- ...buildProjectOptions(project)
194758
- }
194759
- });
194760
- deps.logger.debug(`[task-automation] started sessionId=${result.sessionId} for taskId=${taskId}`);
194761
- await applyAgentTaskUpdate(deps.manager, deps.workspace.id, taskId, {
194762
- status: "in_progress"
194763
- }, {
194764
- agentConfigId
194765
- });
194766
- };
194767
193303
  const openReviewFlock = async (repo, workspaceId) => await repo.openFlockDoc(getReviewPolicyFlockDocId(workspaceId));
194768
193304
  const readReviewPolicy = async (repo, workspaceId) => {
194769
193305
  const handle = await openReviewFlock(repo, workspaceId);
@@ -197008,7 +195544,6 @@ ${trimmed2}${closing}`;
197008
195544
  await runtime.lody.cleanup();
197009
195545
  runtime.unsubscribeTerminalCleanup();
197010
195546
  await runtime.prPollerWorkspace?.dispose();
197011
- await runtime.taskAutomation?.dispose();
197012
195547
  await runtime.reviewAutomation?.dispose();
197013
195548
  } catch (error2) {
197014
195549
  runtime.unsubscribeTerminalCleanup();
@@ -197193,30 +195728,6 @@ ${trimmed2}${closing}`;
197193
195728
  prAssociation: this.cloudPort.prAssociation,
197194
195729
  logger: workspaceLogger
197195
195730
  }) : null;
197196
- const taskAutomation = createTaskAutomationWorkspace({
197197
- documentManager: startedLody.documentManager,
197198
- workspaceId: workspace.id,
197199
- machineId: this.machineId,
197200
- userId: this.userId,
197201
- logger: workspaceLogger,
197202
- startTask: async (taskId, agentConfigId) => {
197203
- const { createSessionResult: createSessionResult2, resolveTurnDispatchConfig: resolveTurnDispatchConfig2 } = await Promise.resolve().then(() => session);
197204
- await startDelegatedTask({
197205
- auth: {
197206
- token: this.cliToken,
197207
- userId: this.userId,
197208
- userName: "",
197209
- userEmail: "",
197210
- machineId: this.machineId,
197211
- machineName: this.machineName
197212
- },
197213
- workspace,
197214
- manager: startedLody.documentManager,
197215
- logger: workspaceLogger,
197216
- createSession: async (args2) => createSessionResult2(args2.auth, args2.workspace, args2.manager, args2.prompt, args2.options, resolveTurnDispatchConfig2({}))
197217
- }, taskId, agentConfigId);
197218
- }
197219
- });
197220
195731
  const reviewAutomation = this.cloudPort.githubTokens ? createReviewAutomation({
197221
195732
  documentManager: startedLody.documentManager,
197222
195733
  workspaceId: workspace.id,
@@ -197267,7 +195778,6 @@ ${trimmed2}${closing}`;
197267
195778
  lody: startedLody,
197268
195779
  unsubscribeTerminalCleanup,
197269
195780
  prPollerWorkspace,
197270
- taskAutomation,
197271
195781
  reviewAutomation
197272
195782
  });
197273
195783
  if (prPollerWorkspace) {
@@ -199343,7 +197853,7 @@ Shutting down gracefully${reason}...`);
199343
197853
  authBaseUrl: LODY_AUTH_URL,
199344
197854
  authSiteUrl: LODY_AUTH_SITE_URL,
199345
197855
  serverBaseUrl: LODY_SERVER_URL,
199346
- previewGatewayUrl: process.env.LODY_PREVIEW_GATEWAY_URL,
197856
+ previewGatewayUrl: "",
199347
197857
  runtimeArtifactsBaseUrl: process.env.LODY_RUNTIME_BASE_URL,
199348
197858
  logger: logger2
199349
197859
  });
@@ -225823,17 +224333,11 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
225823
224333
  }
225824
224334
  async function listSyncableFlockDocIds(manager, workspaceId) {
225825
224335
  const machines = await listAliveDocMetas(manager, isMachineDocRoomId);
225826
- return [
225827
- ...machines.map((entry) => getMachineFlockDocId(workspaceId, entry.meta.id)),
225828
- getTaskIndexFlockDocId(workspaceId)
225829
- ].sort((left2, right2) => left2.localeCompare(right2));
224336
+ return machines.map((entry) => getMachineFlockDocId(workspaceId, entry.meta.id)).sort((left2, right2) => left2.localeCompare(right2));
225830
224337
  }
225831
- function buildSyncDocIds(aliveRoomIds, taskIds) {
224338
+ function buildSyncDocIds(aliveRoomIds) {
225832
224339
  return [
225833
- .../* @__PURE__ */ new Set([
225834
- ...aliveRoomIds,
225835
- ...taskIds.map((taskId) => getTaskRoomId(taskId))
225836
- ])
224340
+ ...aliveRoomIds
225837
224341
  ].sort((left2, right2) => left2.localeCompare(right2));
225838
224342
  }
225839
224343
  async function syncWorkspace(input2) {
@@ -225863,8 +224367,7 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
225863
224367
  });
225864
224368
  return;
225865
224369
  }
225866
- const taskIds = await listWorkspaceTaskIds(manager, workspaceId).catch(() => []);
225867
- const docIds = buildSyncDocIds(await listAliveRoomIds(manager, () => true), taskIds);
224370
+ const docIds = buildSyncDocIds(await listAliveRoomIds(manager, () => true));
225868
224371
  const flockDocIds = await listSyncableFlockDocIds(manager, workspaceId);
225869
224372
  await syncItems({
225870
224373
  summary: summary2,
@@ -226638,58 +225141,6 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
226638
225141
  }
226639
225142
  };
226640
225143
  }
226641
- function formatTaskMarkdown(snapshot) {
226642
- const { meta } = snapshot;
226643
- const lines2 = [
226644
- `# ${meta.title || "Untitled task"}`,
226645
- ""
226646
- ];
226647
- lines2.push(`- Status: ${meta.status}`);
226648
- if (meta.ownerId) {
226649
- lines2.push(`- Owner: ${meta.ownerId}`);
226650
- }
226651
- if (meta.agent?.agentConfigId) {
226652
- lines2.push(`- Agent: ${meta.agent.agentConfigId}`);
226653
- }
226654
- lines2.push("");
226655
- const body2 = snapshot.body.trim();
226656
- lines2.push(body2.length > 0 ? body2 : "_No description._");
226657
- const links = snapshot.links.filter((link2) => link2.removedAt === void 0);
226658
- if (links.length > 0) {
226659
- lines2.push("", "## Links", "");
226660
- for (const link2 of links) {
226661
- lines2.push(link2.kind === "session" ? `- Session \`${link2.sessionId}\`${link2.origin ? ` (${link2.origin})` : ""}` : `- ${link2.url ?? "Pull request"}`);
226662
- }
226663
- }
226664
- const comments = snapshot.timeline.filter((entry) => entry.kind === "comment");
226665
- if (comments.length > 0) {
226666
- lines2.push("", "## Thread", "");
226667
- for (const comment of comments) {
226668
- const author = comment.actorName ?? comment.actorId ?? comment.actorKind;
226669
- lines2.push(`### ${author}`, "", (comment.body ?? "").trim(), "");
226670
- }
226671
- }
226672
- return `${lines2.join("\n").trimEnd()}
226673
- `;
226674
- }
226675
- function buildTaskIndexExportEntry(snapshot) {
226676
- return {
226677
- taskId: snapshot.meta.taskId,
226678
- title: snapshot.meta.title,
226679
- status: snapshot.meta.status,
226680
- createdAt: snapshot.meta.createdAt,
226681
- updatedAt: snapshot.meta.updatedAt,
226682
- relativePath: `tasks/${snapshot.meta.taskId}`
226683
- };
226684
- }
226685
- function sortTasksByCreatedAt(snapshots) {
226686
- return [
226687
- ...snapshots
226688
- ].sort((left2, right2) => {
226689
- const delta = (left2.meta.createdAt ?? 0) - (right2.meta.createdAt ?? 0);
226690
- return delta !== 0 ? delta : left2.meta.taskId.localeCompare(right2.meta.taskId);
226691
- });
226692
- }
226693
225144
  const SESSION_EXPORT_CONCURRENCY = 4;
226694
225145
  const ATTACHMENT_EXPORT_CONCURRENCY = 4;
226695
225146
  function sortSessionsByCreatedAt(sessions) {
@@ -226796,27 +225247,6 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
226796
225247
  relativePath: path__default.posix.join("sessions", sessionDirName)
226797
225248
  };
226798
225249
  }
226799
- async function exportTasks(input2) {
226800
- let taskIds;
226801
- try {
226802
- taskIds = await listWorkspaceTaskIds(input2.manager, input2.workspaceId);
226803
- } catch (error2) {
226804
- input2.warnings.push(`Task export skipped: ${formatErrorMessage(error2)}`);
226805
- return [];
226806
- }
226807
- const snapshots = await mapWithConcurrency$1(taskIds, SESSION_EXPORT_CONCURRENCY, async (taskId) => readTask(input2.manager, taskId).catch((error2) => {
226808
- input2.warnings.push(`Task ${taskId} export failed: ${formatErrorMessage(error2)}`);
226809
- return null;
226810
- }));
226811
- const index = [];
226812
- for (const snapshot of sortTasksByCreatedAt(snapshots.filter((entry) => entry !== null))) {
226813
- const taskDir = path__default.join(input2.outputDir, "tasks", encodeExportPathSegment(snapshot.meta.taskId, "task"));
226814
- await writeJson(path__default.join(taskDir, "task.json"), snapshot);
226815
- await writeText(path__default.join(taskDir, "task.md"), formatTaskMarkdown(snapshot));
226816
- index.push(buildTaskIndexExportEntry(snapshot));
226817
- }
226818
- return index;
226819
- }
226820
225250
  async function exportWorkspaceData(options) {
226821
225251
  const downloadImages = options.downloadImages !== false;
226822
225252
  const warnings = [];
@@ -226834,13 +225264,6 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
226834
225264
  warnings
226835
225265
  }));
226836
225266
  await writeJson(path__default.join(options.outputDir, "sessions", "index.json"), sessionIndex);
226837
- const taskIndex = await exportTasks({
226838
- manager: options.manager,
226839
- workspaceId: options.workspace.id,
226840
- outputDir: options.outputDir,
226841
- warnings
226842
- });
226843
- await writeJson(path__default.join(options.outputDir, "tasks", "index.json"), taskIndex);
226844
225267
  let usageExported = false;
226845
225268
  try {
226846
225269
  const usageBundle = await fetchWorkspaceUsageBundle({
@@ -226863,7 +225286,7 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
226863
225286
  },
226864
225287
  outputDir: options.outputDir,
226865
225288
  sessionCount: sessionIndex.length,
226866
- taskCount: taskIndex.length,
225289
+ taskCount: 0,
226867
225290
  usageExported
226868
225291
  };
226869
225292
  await writeJson(path__default.join(options.outputDir, "manifest.json"), manifest);
@@ -226888,11 +225311,6 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
226888
225311
  await mapWithConcurrency$1(sessions, EXPORT_SYNC_CONCURRENCY, async (entry) => {
226889
225312
  await syncDocForRead(manager, getSessionRoomId(entry.meta.id), `export:${workspace.id}:${entry.meta.id}`);
226890
225313
  });
226891
- const workspaceId = workspace.id;
226892
- const taskIds = await listWorkspaceTaskIds(manager, workspaceId).catch(() => []);
226893
- await mapWithConcurrency$1(taskIds, EXPORT_SYNC_CONCURRENCY, async (taskId) => {
226894
- await syncDocForRead(manager, getTaskRoomId(taskId), `export:${workspace.id}:${taskId}`);
226895
- });
226896
225314
  }
226897
225315
  const exportCommand = new Command("export").description("Export user-facing workspace session data").option("--workspace <selector>", "Target workspace id, slug, or name").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) => {
226898
225316
  await runOneShotCommand("export", options, async () => {
@@ -227035,7 +225453,7 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
227035
225453
  data = createReviewBundleSnapshot(bundle);
227036
225454
  }
227037
225455
  const { injectReviewSnapshot } = await import("./chunks/index-VoI6Ds2-.js");
227038
- const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-D_i2QTRo.js").then(async (m) => {
225456
+ const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-B9jEGZSx.js").then(async (m) => {
227039
225457
  await m.__tla;
227040
225458
  return m;
227041
225459
  });
@@ -245237,62 +243655,6 @@ ${result.stdout ?? ""}`;
245237
243655
  });
245238
243656
  return FeedbackSubmissionResultSchema.parse(raw2);
245239
243657
  }
245240
- const formatError = (error2) => error2 instanceof Error ? error2.message : String(error2);
245241
- const syncProposalDoc = async (manager, roomId, phase) => {
245242
- try {
245243
- await manager.syncDocOrThrow(roomId, {
245244
- reason: `mcp.task_propose:${phase}`
245245
- });
245246
- } catch (error2) {
245247
- const detail = phase === "hydrate" ? "The conversation could not be synchronized before writing the task proposal." : "The task proposal was saved locally, but remote synchronization was not confirmed.";
245248
- throw new LodyOperationStoreError("TASK_PROPOSAL_SYNC_FAILED", `${detail} Retry with the same proposalId; retries are idempotent. ${formatError(error2)}`, true);
245249
- }
245250
- };
245251
- const publishTaskProposal = async (manager, sessionId, draft, actor, options = {}) => {
245252
- const doc = await manager.getOrCreateSessionDoc(sessionId);
245253
- await syncProposalDoc(manager, doc.roomId, "hydrate");
245254
- const desiredMeta = {
245255
- proposalId: draft.proposalId,
245256
- title: draft.title,
245257
- ...draft.body !== void 0 ? {
245258
- body: draft.body
245259
- } : {},
245260
- proposedBy: {
245261
- kind: "agent",
245262
- ...actor.agentConfigId ? {
245263
- agentConfigId: actor.agentConfigId
245264
- } : {},
245265
- ...actor.name ? {
245266
- name: actor.name
245267
- } : {}
245268
- }
245269
- };
245270
- const turnId = `task-proposal-${draft.proposalId}`;
245271
- let changed = false;
245272
- let result = {
245273
- pending: true
245274
- };
245275
- const applied = await doc.sessionData.commands.applyHistoryAction({
245276
- kind: "task-proposal",
245277
- turnId,
245278
- meta: desiredMeta,
245279
- timestamp: new Date((options.now ?? getServerNow)()).toISOString()
245280
- }).catch((error2) => {
245281
- if (!(error2 instanceof HistoryActionRefused)) throw error2;
245282
- throw new LodyOperationStoreError("TASK_PROPOSAL_ID_CONFLICT", "History turn already belongs to a different task proposal", false);
245283
- });
245284
- const accepted = applied;
245285
- changed = accepted.matched ?? false;
245286
- result = accepted.proposal ?? {
245287
- pending: true
245288
- };
245289
- if (!changed) {
245290
- return result;
245291
- }
245292
- await manager.repo.flush();
245293
- await syncProposalDoc(manager, doc.roomId, "commit");
245294
- return result;
245295
- };
245296
243658
  const jsonBytes = (value) => Buffer.byteLength(JSON.stringify(value), "utf8");
245297
243659
  const encodeSessionHistoryCursor = (cursor) => Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
245298
243660
  const parseSessionHistoryCursor = (cursor, sessionId, newestBeforeIndex) => {
@@ -245420,83 +243782,6 @@ ${result.stdout ?? ""}`;
245420
243782
  maxBytes: params.maxBytes
245421
243783
  });
245422
243784
  }
245423
- const MIME_TYPE_BY_EXTENSION = {
245424
- png: "image/png",
245425
- jpg: "image/jpeg",
245426
- jpeg: "image/jpeg",
245427
- webp: "image/webp",
245428
- gif: "image/gif"
245429
- };
245430
- const readTaskImage = async (filePath) => {
245431
- const absolutePath = path__default$1.resolve(filePath);
245432
- let handle;
245433
- try {
245434
- handle = await fs__default$1.promises.open(absolutePath, fs__default$1.constants.O_RDONLY | fs__default$1.constants.O_NOFOLLOW);
245435
- } catch (error2) {
245436
- const code2 = error2?.code;
245437
- throw new Error(code2 === "ELOOP" ? `Image path must not be a symlink: ${filePath}` : `Image file not found: ${filePath}`, {
245438
- cause: error2
245439
- });
245440
- }
245441
- try {
245442
- const stat2 = await handle.stat();
245443
- if (!stat2.isFile()) throw new Error(`Image path is not a file: ${filePath}`);
245444
- if (stat2.size <= 0) throw new Error(`Image is empty: ${filePath}`);
245445
- if (stat2.size > SESSION_IMAGE_MAX_SIZE_BYTES) {
245446
- throw new Error(`Image must be <= ${Math.floor(SESSION_IMAGE_MAX_SIZE_BYTES / (1024 * 1024))}MB: ${filePath}`);
245447
- }
245448
- const fileName = path__default$1.basename(absolutePath);
245449
- const extension2 = path__default$1.extname(fileName).slice(1).toLowerCase();
245450
- const mimeType = MIME_TYPE_BY_EXTENSION[extension2];
245451
- if (!mimeType) throw new Error(`Unsupported image file extension: ${fileName}`);
245452
- return {
245453
- fileName,
245454
- mimeType,
245455
- bytes: await handle.readFile()
245456
- };
245457
- } finally {
245458
- await handle.close();
245459
- }
245460
- };
245461
- const uploadTaskImages = async (args2) => {
245462
- const serverUrl = LODY_SERVER_URL?.trim();
245463
- if (!serverUrl) throw new Error("LODY_SERVER_URL is not defined");
245464
- const uploadUrl = buildTaskImageApiUrl(serverUrl, getTaskImageUploadApiPath(args2.workspaceId));
245465
- const results = [];
245466
- for (const filePath of args2.paths) {
245467
- const file2 = await readTaskImage(filePath);
245468
- const bytes2 = new Uint8Array(file2.bytes.byteLength);
245469
- bytes2.set(file2.bytes);
245470
- const formData = new FormData();
245471
- formData.set("file", new Blob([
245472
- bytes2
245473
- ], {
245474
- type: file2.mimeType
245475
- }), file2.fileName);
245476
- const response2 = await fetch(uploadUrl, {
245477
- method: "POST",
245478
- headers: {
245479
- Authorization: `Bearer ${args2.token}`
245480
- },
245481
- body: formData
245482
- });
245483
- if (!response2.ok) {
245484
- const detail = await response2.text().catch(() => "");
245485
- throw new Error(`Failed to upload task image (${response2.status})${detail ? `: ${detail.slice(0, 200)}` : ""}`);
245486
- }
245487
- const body2 = await response2.json().catch(() => null);
245488
- const image = body2 && typeof body2 === "object" && "image" in body2 ? body2.image : void 0;
245489
- if (!image || typeof image !== "object" || typeof image.imageId !== "string" || typeof image.mimeType !== "string" || typeof image.sizeBytes !== "number") {
245490
- throw new Error("Invalid task image upload payload");
245491
- }
245492
- const payload = image;
245493
- results.push({
245494
- ...payload,
245495
- markdownUrl: buildTaskImageMarkdownUrl(payload.imageId)
245496
- });
245497
- }
245498
- return results;
245499
- };
245500
243785
  async function syncMcpCatalog(syncer, workspaceId) {
245501
243786
  await syncer.syncFlockDocOrThrow(getWorkspaceFlockDocId(workspaceId), {
245502
243787
  timeoutMs: 1e4,
@@ -245741,19 +244026,10 @@ ${result.stdout ?? ""}`;
245741
244026
  const SESSION_RENAME_MANY_TOOL_NAME = "lody_session_rename_many";
245742
244027
  const OPERATION_GET_TOOL_NAME = "lody_operation_get";
245743
244028
  const OPERATION_CANCEL_TOOL_NAME = "lody_operation_cancel";
245744
- const TASK_LIST_TOOL_NAME = "lody_task_list";
245745
- const TASK_GET_TOOL_NAME = "lody_task_get";
245746
- const TASK_CREATE_TOOL_NAME = "lody_task_create";
245747
- const TASK_PROPOSE_TOOL_NAME = "lody_task_propose";
245748
- const TASK_UPDATE_TOOL_NAME = "lody_task_update";
245749
- const TASK_EDIT_BODY_TOOL_NAME = "lody_task_edit_body";
245750
- const TASK_COMMENT_TOOL_NAME = "lody_task_comment";
245751
- const TASK_IMAGE_UPLOAD_TOOL_NAME = "lody_task_upload_images";
245752
244029
  const REVIEW_SUBMIT_TOOL_NAME = "lody_review_submit";
245753
244030
  const SESSION_FILE_MAX_SIZE_MB = Math.floor(SESSION_FILE_MAX_SIZE_BYTES / (1024 * 1024));
245754
244031
  const SESSION_CONTROL_TIMEOUT_MS = 3e4;
245755
244032
  const LODY_CLI_DEFAULT_TIMEOUT_MS = 10 * 6e4;
245756
- const escapeMarkdownImageAlt = (value) => value.replaceAll(/[\\\]]/gu, "\\$&");
245757
244033
  const MAX_MCP_SESSION_WAIT_TIMEOUT_SECONDS = 3600;
245758
244034
  const MAX_MCP_COMMAND_BATCH_SIZE = 20;
245759
244035
  const MAX_MCP_STATUS_BATCH_SIZE = 50;
@@ -245764,11 +244040,6 @@ ${result.stdout ?? ""}`;
245764
244040
  const MAX_MCP_SESSION_HISTORY_LIMIT = 50;
245765
244041
  const MAX_MCP_SESSION_HISTORY_BYTES = 128 * 1024;
245766
244042
  const MAX_MCP_SESSION_TITLE_CHARS = 200;
245767
- const MAX_MCP_TASK_BODY_BYTES = 64 * 1024;
245768
- const MAX_MCP_TASK_LINKS = 50;
245769
- const MAX_MCP_TASK_EDIT_CHARS = 64e3;
245770
- const DEFAULT_MCP_TASK_LIST_LIMIT = 20;
245771
- const MAX_MCP_TASK_LIST_LIMIT = 100;
245772
244043
  const FILE_UPLOAD_TIMEOUT_MS = 10 * 6e4;
245773
244044
  const PreviewToolInputSchema = object$1({
245774
244045
  protocol: literal$1("http").default("http"),
@@ -245783,9 +244054,6 @@ ${result.stdout ?? ""}`;
245783
244054
  const ImageUploadToolInputSchema = object$1({
245784
244055
  paths: array$2(string$1().trim().min(1).describe("Absolute path or session-workspace-relative path to an image file.")).min(1).max(SESSION_IMAGE_MAX_COUNT).describe("Image file paths to upload to the current Lody conversation.")
245785
244056
  }).strict();
245786
- const TaskImageUploadToolInputSchema = object$1({
245787
- paths: array$2(string$1().trim().min(1).describe("Absolute path or session-workspace-relative path to an image file.")).min(1).max(SESSION_IMAGE_MAX_COUNT).describe("Images to upload for use in a task description or comment.")
245788
- }).strict();
245789
244057
  const FileUploadToolInputSchema = object$1({
245790
244058
  paths: array$2(string$1().trim().min(1).describe("Absolute path or session-workspace-relative path to a file.")).min(1).max(SESSION_FILE_MAX_COUNT).describe("File paths to upload to the current Lody conversation.")
245791
244059
  }).strict();
@@ -246113,7 +244381,7 @@ ${result.stdout ?? ""}`;
246113
244381
  cursor: string$1().trim().min(1).optional()
246114
244382
  }).strict();
246115
244383
  const SessionHistoryToolInputSchema = object$1({
246116
- sessionId: string$1().trim().min(1).optional().describe("Target session id, or current. Defaults to current."),
244384
+ sessionId: string$1().trim().min(1).optional().describe("Target session id, or current. Defaults to current. Also accepts a `session://<sessionId>` URI from a session mention link."),
246117
244385
  cursor: string$1().trim().min(1).optional(),
246118
244386
  limit: number$4().int().positive().max(MAX_MCP_SESSION_HISTORY_LIMIT).optional().describe(`Maximum transcript turns to return. Defaults to ${DEFAULT_MCP_SESSION_HISTORY_LIMIT}.`)
246119
244387
  }).strict();
@@ -246140,8 +244408,7 @@ ${result.stdout ?? ""}`;
246140
244408
  workspaceId: readRequiredEnv("LODY_MCP_WORKSPACE_ID", "LODY_PREVIEW_MCP_WORKSPACE_ID"),
246141
244409
  sessionId: SessionIdSchema$1.parse(readRequiredEnv("LODY_MCP_SESSION_ID", "LODY_PREVIEW_MCP_SESSION_ID")),
246142
244410
  localControlSocketPath: readOptionalEnv("LODY_MCP_SOCKET_PATH", "LODY_PREVIEW_MCP_SOCKET_PATH"),
246143
- workdir: readOptionalEnv("LODY_MCP_WORKDIR", "LODY_PREVIEW_MCP_WORKDIR") ?? process.cwd(),
246144
- taskToolsEnabled: readOptionalEnv("LODY_MCP_TASK_TOOLS_ENABLED") === "1"
244411
+ workdir: readOptionalEnv("LODY_MCP_WORKDIR", "LODY_PREVIEW_MCP_WORKDIR") ?? process.cwd()
246145
244412
  };
246146
244413
  const sharedOperationStores = /* @__PURE__ */ new Map();
246147
244414
  const resolveOperationStorePathForContext = () => getLodyOperationStorePath(getSessionContext().machineId);
@@ -246300,9 +244567,14 @@ ${result.stdout ?? ""}`;
246300
244567
  return JSON.parse(line3);
246301
244568
  };
246302
244569
  const runLodyCliJson = async (args2, timeoutMs) => parseJsonCliOutput((await runLodyCli(args2, timeoutMs)).stdout);
244570
+ const SESSION_URI_PREFIX = "session://";
244571
+ const stripSessionUriPrefix = (value) => value.startsWith(SESSION_URI_PREFIX) ? value.slice(SESSION_URI_PREFIX.length) : value;
246303
244572
  const resolveMcpSessionId = (sessionId, ctx) => {
246304
244573
  const normalized = normalizeCliValue(sessionId);
246305
- return normalized && normalized !== "current" ? normalized : ctx.sessionId;
244574
+ if (!normalized || normalized === "current") {
244575
+ return ctx.sessionId;
244576
+ }
244577
+ return stripSessionUriPrefix(normalized);
246306
244578
  };
246307
244579
  const getMcpWorkspaceId = (ctx) => ctx.workspaceId;
246308
244580
  const buildStructuredOutputOptions = (args2, outputMode = "json", onEvent) => {
@@ -246374,10 +244646,7 @@ ${prompt2}` : prompt2;
246374
244646
  return {
246375
244647
  input: input2,
246376
244648
  prompt: input2.prompt,
246377
- dispatchConfig: {
246378
- ...buildMcpTurnDispatchConfig(input2),
246379
- taskToolsEnabled: invoking?.frozenInputConfig.taskToolsEnabled === true
246380
- }
244649
+ dispatchConfig: buildMcpTurnDispatchConfig(input2)
246381
244650
  };
246382
244651
  }
246383
244652
  if (!role || role.id !== input2.agentRoleId) {
@@ -246416,7 +244685,6 @@ ${prompt2}` : prompt2;
246416
244685
  prompt: composeAgentRolePrompt(role.promptPrefix, input2.prompt),
246417
244686
  dispatchConfig: {
246418
244687
  ...role.runConfig,
246419
- taskToolsEnabled: invoking?.frozenInputConfig.taskToolsEnabled === true,
246420
244688
  inheritSessionDefaults: false
246421
244689
  },
246422
244690
  role
@@ -246985,16 +245253,6 @@ ${prompt2}` : prompt2;
246985
245253
  inputConfig
246986
245254
  };
246987
245255
  };
246988
- const assertInvokingTurnTaskToolsEnabled = async (manager, sessionId) => {
246989
- const session2 = await readCurrentSessionMeta(manager, sessionId);
246990
- if (!session2) {
246991
- throw new LodyOperationStoreError("SESSION_NOT_FOUND", `Requester Session not found: ${sessionId}`, false);
246992
- }
246993
- const source = await resolveInvokingTurnSource();
246994
- if (source.inputConfig.taskToolsEnabled !== true) {
246995
- throw new LodyOperationStoreError("TASK_TOOLS_DISABLED", "Lody Task tools are disabled for the driving user turn.", false);
246996
- }
246997
- };
246998
245256
  const resolveInvokingTurnContext = async (session2) => {
246999
245257
  const source = await resolveInvokingTurnSource();
247000
245258
  const chainDepth = source.inputConfig.chainDepth ?? 0;
@@ -247447,10 +245705,7 @@ ${prompt2}` : prompt2;
247447
245705
  throw new Error("Single chat Operation is missing its active target item.");
247448
245706
  }
247449
245707
  if (!pendingItem.inputDurable && accepted.claimedItemIndexes.includes(0)) {
247450
- const result = await sendSessionChatResult(auth, workspace, manager, pendingItem.target.sessionId, args2.prompt, {
247451
- ...resolveTurnDispatchConfig({}),
247452
- taskToolsEnabled: invoking.frozenInputConfig.taskToolsEnabled === true
247453
- }, void 0, void 0, {
245708
+ const result = await sendSessionChatResult(auth, workspace, manager, pendingItem.target.sessionId, args2.prompt, resolveTurnDispatchConfig({}), void 0, void 0, {
247454
245709
  userTurnId: pendingItem.target.userTurnId,
247455
245710
  chainDepth: invoking.chainDepth + 1
247456
245711
  }, toDelegatedSessionRequester(invoking.identity));
@@ -247873,10 +246128,7 @@ ${prompt2}` : prompt2;
247873
246128
  return batchFailure("INVALID_ITEM", "Chat item requires sessionId and prompt.", false, storedItem.label, storedItem.target);
247874
246129
  }
247875
246130
  try {
247876
- await sendSessionChatResult(auth, workspace, manager, storedItem.target.sessionId, expandedItem.prompt, {
247877
- ...resolveTurnDispatchConfig({}),
247878
- taskToolsEnabled: invoking.frozenInputConfig.taskToolsEnabled === true
247879
- }, void 0, void 0, {
246131
+ await sendSessionChatResult(auth, workspace, manager, storedItem.target.sessionId, expandedItem.prompt, resolveTurnDispatchConfig({}), void 0, void 0, {
247880
246132
  userTurnId: storedItem.target.userTurnId,
247881
246133
  chainDepth: invoking.chainDepth + 1,
247882
246134
  bypassSessionQuota: shouldBypassSessionQuota("session_chat_many")
@@ -247891,103 +246143,6 @@ ${prompt2}` : prompt2;
247891
246143
  return snapshotOperation(ctx.sessionId, args2.operationId);
247892
246144
  });
247893
246145
  };
247894
- const TaskGetToolInputSchema = object$1({
247895
- taskId: string$1().trim().min(1).describe("Task id to read.")
247896
- }).strict();
247897
- const TaskStatusInputSchema = _enum$1(TASK_STATUS_VALUES);
247898
- const TaskPriorityInputSchema = _enum$1(TASK_PRIORITY_VALUES);
247899
- const TaskLabelsInputSchema = array$2(string$1().trim().min(1).max(TASK_LABEL_MAX_LENGTH)).max(TASK_LABEL_MAX_COUNT);
247900
- const TASK_OWNER_SELF_ALIAS = "me";
247901
- const TaskOwnerIdWriteSchema = string$1().trim().refine((value) => value === "", {
247902
- message: 'Agents may only unassign an owner: pass "" . Assigning a person is a human act, and "me" is a lody_task_list filter rather than a user id.'
247903
- });
247904
- const TaskProjectInputSchema = discriminatedUnion("kind", [
247905
- object$1({
247906
- kind: literal$1("github"),
247907
- repo: string$1().trim().min(1).describe("GitHub repo full name, such as owner/repo."),
247908
- branch: string$1().trim().min(1).optional().describe("Base branch; defaults to main.")
247909
- }).strict(),
247910
- object$1({
247911
- kind: literal$1("local"),
247912
- projectId: string$1().trim().min(1).describe("Local project id returned by lody_session_create_options."),
247913
- branch: string$1().trim().min(1).optional().describe("Optional Git branch."),
247914
- worktree: boolean().optional().describe("Run the task in an isolated local git worktree for the project.")
247915
- }).strict()
247916
- ]);
247917
- const DEFAULT_TASK_GITHUB_BRANCH = "main";
247918
- const toTaskProjectRef = (input2) => input2.kind === "github" ? {
247919
- kind: "github",
247920
- repoFullName: input2.repo,
247921
- branch: input2.branch ?? DEFAULT_TASK_GITHUB_BRANCH
247922
- } : {
247923
- kind: "local",
247924
- localProjectId: input2.projectId,
247925
- ...input2.branch ? {
247926
- branch: input2.branch
247927
- } : {},
247928
- ...input2.worktree ? {
247929
- useWorktree: true
247930
- } : {}
247931
- };
247932
- const TaskListToolInputSchema = object$1({
247933
- status: array$2(TaskStatusInputSchema).min(1).max(TASK_STATUS_VALUES.length).optional().describe("Keep only these statuses."),
247934
- ownerId: string$1().trim().optional().describe('Owner user id, "me" for the signed-in operator, or "" for unassigned tasks.'),
247935
- hasAgent: boolean().optional().describe("true keeps only tasks entrusted to an agent; false keeps only tasks without one."),
247936
- titleContains: string$1().trim().min(1).max(200).optional().describe("Case-insensitive substring of the title."),
247937
- limit: number$4().int().min(1).max(MAX_MCP_TASK_LIST_LIMIT).optional().describe(`Maximum rows to return. Default ${DEFAULT_MCP_TASK_LIST_LIMIT}.`)
247938
- }).strict();
247939
- const TaskCreateToolInputSchema = object$1({
247940
- title: string$1().trim().min(1).max(200).describe("Short title for the task."),
247941
- body: string$1().max(2e4).optional().describe("Markdown description: context, acceptance criteria, links."),
247942
- status: TaskStatusInputSchema.optional().describe("Defaults to backlog."),
247943
- priority: TaskPriorityInputSchema.optional().describe("Omit to leave the task untriaged."),
247944
- labels: TaskLabelsInputSchema.optional(),
247945
- ownerId: TaskOwnerIdWriteSchema.optional().describe('Pass "" to create the task unassigned. Omit it to own the task as the signed-in operator; you cannot assign it to someone else.'),
247946
- project: TaskProjectInputSchema.optional().describe("Repository or local project this work belongs to.")
247947
- }).strict();
247948
- const TaskProposeToolInputSchema = object$1({
247949
- proposalId: string$1().trim().min(1).max(64).describe("Caller-chosen stable id so re-proposing the same work does not stack up cards."),
247950
- title: string$1().trim().min(1).max(200).describe("Short title for the proposed task."),
247951
- body: string$1().max(2e4).optional().describe("Markdown draft for the task description.")
247952
- }).strict();
247953
- const TASK_UPDATE_FIELDS = [
247954
- "status",
247955
- "title",
247956
- "ownerId",
247957
- "priority",
247958
- "labels",
247959
- "project",
247960
- "pullRequestUrl"
247961
- ];
247962
- const TaskUpdateToolInputSchema = object$1({
247963
- taskId: string$1().trim().min(1),
247964
- status: TaskStatusInputSchema.optional().describe("New task status. done and canceled are recorded in the task thread with your name; they do not notify the owner, so if a person needs to know, leave a comment."),
247965
- title: string$1().trim().min(1).max(200).optional().describe("Replacement title."),
247966
- ownerId: TaskOwnerIdWriteSchema.optional().describe('Pass "" to clear the owner. Assigning the task to a person is a human act and is not available here; ask the owner in a comment instead.'),
247967
- priority: union$7([
247968
- TaskPriorityInputSchema,
247969
- literal$1("none")
247970
- ]).optional().describe('New priority, or "none" to clear it.'),
247971
- labels: TaskLabelsInputSchema.optional().describe("Replaces the whole label set; pass [] to clear."),
247972
- project: TaskProjectInputSchema.optional().describe("Repository or local project this work belongs to."),
247973
- pullRequestUrl: string$1().trim().url().optional().describe("Pull request produced by this work. Linking it delegates task completion to the pull request.")
247974
- }).strict().superRefine((value, ctx) => {
247975
- if (TASK_UPDATE_FIELDS.every((field) => value[field] === void 0)) {
247976
- ctx.addIssue({
247977
- code: ZodIssueCode$1.custom,
247978
- message: `Provide at least one field to change: ${TASK_UPDATE_FIELDS.join(", ")}.`
247979
- });
247980
- }
247981
- });
247982
- const TaskEditBodyToolInputSchema = object$1({
247983
- taskId: string$1().trim().min(1),
247984
- oldString: string$1().max(MAX_MCP_TASK_EDIT_CHARS).describe("Exact text to replace in the current body. Use an empty string to append a new section."),
247985
- newString: string$1().max(MAX_MCP_TASK_EDIT_CHARS).describe("Replacement text.")
247986
- }).strict();
247987
- const TaskCommentToolInputSchema = object$1({
247988
- taskId: string$1().trim().min(1),
247989
- body: string$1().trim().min(1).max(2e4).describe("Markdown comment to add to the task.")
247990
- }).strict();
247991
246146
  const ReviewSubmitToolInputSchema = object$1({
247992
246147
  verdict: _enum$1(REVIEW_VERDICT_VALUES).describe("`approve` only when nothing blocking remains."),
247993
246148
  findings: array$2(object$1({
@@ -248009,145 +246164,17 @@ ${prompt2}` : prompt2;
248009
246164
  })).max(100).optional().describe("Verdict on each previously raised finding. Use `disputed` to escalate to a human."),
248010
246165
  summary: string$1().trim().max(2e3).optional()
248011
246166
  }).strict();
248012
- const resolveTaskPrProvider = (url) => url.includes("gitlab") ? "gitlab" : "github";
248013
- const buildTaskListFilter = (args2, operatorUserId) => ({
248014
- ...args2.status ? {
248015
- status: args2.status
248016
- } : {},
248017
- ...args2.ownerId !== void 0 ? {
248018
- ownerId: args2.ownerId === TASK_OWNER_SELF_ALIAS ? operatorUserId : args2.ownerId
248019
- } : {},
248020
- ...args2.hasAgent !== void 0 ? {
248021
- hasAgent: args2.hasAgent
248022
- } : {},
248023
- ...args2.titleContains ? {
248024
- titleContains: args2.titleContains
248025
- } : {},
248026
- limit: args2.limit ?? DEFAULT_MCP_TASK_LIST_LIMIT
248027
- });
248028
- const buildTaskUpdateInput = (args2, sessionId) => ({
248029
- ...args2.status ? {
248030
- status: args2.status
248031
- } : {},
248032
- ...args2.title !== void 0 ? {
248033
- title: args2.title
248034
- } : {},
248035
- ...args2.ownerId !== void 0 ? {
248036
- ownerId: args2.ownerId
248037
- } : {},
248038
- ...args2.priority !== void 0 ? {
248039
- priority: args2.priority === "none" ? null : args2.priority
248040
- } : {},
248041
- ...args2.labels !== void 0 ? {
248042
- labels: args2.labels
248043
- } : {},
248044
- ...args2.project ? {
248045
- projects: [
248046
- toTaskProjectRef(args2.project)
248047
- ]
248048
- } : {},
248049
- ...args2.pullRequestUrl ? {
248050
- pullRequest: {
248051
- url: args2.pullRequestUrl,
248052
- provider: resolveTaskPrProvider(args2.pullRequestUrl),
248053
- originSessionId: sessionId
248054
- }
248055
- } : {}
248056
- });
248057
- const resolveTaskActor = async (manager, sessionId) => {
248058
- const session2 = await readCurrentSessionMeta(manager, sessionId);
248059
- if (!session2?.agentConfigId) {
248060
- return {};
248061
- }
248062
- const config2 = await manager.getAgentConfigById(session2.agentConfigId).catch(() => void 0);
248063
- return {
248064
- agentConfigId: session2.agentConfigId,
248065
- ...config2?.name ? {
248066
- name: config2.name
248067
- } : {}
248068
- };
248069
- };
248070
- const summarizeTaskBodyForMcp = (body2, key2) => {
248071
- const bounded = truncateSessionHistoryText(body2, MAX_MCP_TASK_BODY_BYTES);
248072
- return "truncated" in bounded ? {
248073
- [key2]: bounded.text,
248074
- bodyTruncated: true,
248075
- bodyOmittedBytes: bounded.omittedBytes
248076
- } : {
248077
- [key2]: bounded.text
248078
- };
248079
- };
248080
- const summarizeTaskIndexRowForMcp = (row) => ({
248081
- taskId: row.taskId,
248082
- title: row.title,
248083
- status: row.status,
248084
- ownerId: row.ownerId,
248085
- ...row.priority ? {
248086
- priority: row.priority
248087
- } : {},
248088
- ...row.labels && row.labels.length > 0 ? {
248089
- labels: row.labels
248090
- } : {},
248091
- hasAgent: Boolean(row.hasAgent),
248092
- ...row.projectKind ? {
248093
- projectKind: row.projectKind,
248094
- projectKey: row.projectKey
248095
- } : {},
248096
- sessionCount: row.sessionCount ?? 0,
248097
- prCount: row.prCount ?? 0,
248098
- updatedAt: row.updatedAt
248099
- });
248100
- const summarizeTaskForMcp = (snapshot) => {
248101
- const sessionLinks = getActiveTaskSessionLinks(snapshot.links);
248102
- const prLinks = getActiveTaskPrLinks(snapshot.links);
248103
- const allComments = snapshot.timeline.filter((entry) => entry.kind === "comment");
248104
- const projects = snapshot.meta.projects ?? [];
248105
- return {
248106
- taskId: snapshot.meta.taskId,
248107
- title: snapshot.meta.title,
248108
- status: snapshot.meta.status,
248109
- ownerId: snapshot.meta.ownerId,
248110
- ...snapshot.meta.priority ? {
248111
- priority: snapshot.meta.priority
248112
- } : {},
248113
- ...snapshot.meta.labels && snapshot.meta.labels.length > 0 ? {
248114
- labels: snapshot.meta.labels
248115
- } : {},
248116
- hasAgent: Boolean(snapshot.meta.agent),
248117
- ...projects.length > 0 ? {
248118
- projects: projects.map((project) => summarizeProjectRefForMcp(project))
248119
- } : {},
248120
- ...summarizeTaskBodyForMcp(snapshot.body, "body"),
248121
- sessions: sessionLinks.slice(-MAX_MCP_TASK_LINKS).map((link2) => ({
248122
- sessionId: link2.sessionId,
248123
- origin: link2.origin
248124
- })),
248125
- ...sessionLinks.length > MAX_MCP_TASK_LINKS ? {
248126
- sessionCount: sessionLinks.length
248127
- } : {},
248128
- pullRequests: prLinks.slice(-MAX_MCP_TASK_LINKS).map((link2) => ({
248129
- url: link2.url,
248130
- provider: link2.provider
248131
- })),
248132
- ...prLinks.length > MAX_MCP_TASK_LINKS ? {
248133
- pullRequestCount: prLinks.length
248134
- } : {},
248135
- comments: allComments.slice(-20).map((entry) => ({
248136
- actor: entry.actorKind,
248137
- actorName: entry.actorName,
248138
- body: entry.body,
248139
- createdAt: entry.createdAt
248140
- })),
248141
- ...allComments.length > 20 ? {
248142
- commentCount: allComments.length
248143
- } : {}
248144
- };
248145
- };
248146
- function buildLodyMcpServer(config2 = {}) {
246167
+ function buildLodyMcpServer() {
248147
246168
  initCliAnalytics();
248148
246169
  const server = new McpServer({
248149
246170
  name: "lody",
248150
246171
  version: "0.1.0"
246172
+ }, {
246173
+ instructions: [
246174
+ "Session mentions in user messages may appear as markdown links of the form [@Title](session://<sessionId>).",
246175
+ "To read that conversation, call lody_session_history with sessionId set to the <sessionId> (the part after session://), or pass the full session:// URI.",
246176
+ "Paginate with nextCursor when you need older turns."
246177
+ ].join(" ")
248151
246178
  });
248152
246179
  server.registerTool(FEEDBACK_TOOL_NAME, {
248153
246180
  title: "Send feedback about Lody",
@@ -248303,37 +246330,6 @@ ${prompt2}` : prompt2;
248303
246330
  return textResult(`Failed to upload images: ${String(error2)}`, true);
248304
246331
  }
248305
246332
  });
248306
- const taskImageUploadTool = server.registerTool(TASK_IMAGE_UPLOAD_TOOL_NAME, {
248307
- title: "Upload images for a Lody task",
248308
- description: "Upload local images to the current workspace and return stable Markdown image references. Use the returned markdown in lody_task_comment, lody_task_edit_body, or lody_task_propose. Unlike lody_upload_images, this does not add anything to the current conversation.",
248309
- inputSchema: TaskImageUploadToolInputSchema
248310
- }, async (args2) => {
248311
- try {
248312
- const ctx = getSessionContext();
248313
- const auth = getAuthContextOrThrow$1("mcp");
248314
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248315
- await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248316
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248317
- });
248318
- const images = await uploadTaskImages({
248319
- paths: args2.paths.map((filePath) => resolveUploadPath(filePath, ctx.workdir)),
248320
- workspaceId: workspace.id,
248321
- token: auth.token
248322
- });
248323
- return jsonTextResult({
248324
- ok: true,
248325
- images: images.map((image) => ({
248326
- imageId: image.imageId,
248327
- fileName: image.fileName,
248328
- mimeType: image.mimeType,
248329
- sizeBytes: image.sizeBytes,
248330
- markdown: `![${escapeMarkdownImageAlt(image.fileName ?? "image")}](${image.markdownUrl})`
248331
- }))
248332
- });
248333
- } catch (error2) {
248334
- return mcpErrorResult(error2);
248335
- }
248336
- });
248337
246333
  server.registerTool(FILE_UPLOAD_TOOL_NAME, {
248338
246334
  title: "Upload files to Lody conversation",
248339
246335
  description: `Use this when the user explicitly asks you to send, attach, share, or provide a downloadable file artifact in the current Lody chat (logs, reports, data, archives, binaries, documents, etc.). Do not use this merely because a file exists in the workspace: Lody can show ordinary workspace files through its file browser, so give a workspace-relative path when the user only needs to inspect one. Upload 1-${SESSION_FILE_MAX_COUNT} local files of any type (max ${SESSION_FILE_MAX_SIZE_MB} MB each). Each file is attached to this conversation as a downloadable attachment; the user can download it and, for plain-text files, preview it inline. No reusable URL is returned and nothing is written to the workspace file area. Paths may be absolute or relative to the current session workspace (which can differ from shell cwd) but must point inside the session workspace; files elsewhere on the host are rejected. Missing, unreadable, oversized (> ${SESSION_FILE_MAX_SIZE_MB} MB), or empty files are rejected with an error identifying which path failed and why.`,
@@ -248652,7 +246648,7 @@ ${lines2.join("\n")}` : ""}${suffix}`);
248652
246648
  });
248653
246649
  server.registerTool(SESSION_HISTORY_TOOL_NAME, {
248654
246650
  title: "Read Lody session history",
248655
- description: `Read one bounded visible transcript page, oldest-to-newest. Omit cursor for the newest page; nextCursor reads older entries. Defaults to ${DEFAULT_MCP_SESSION_HISTORY_LIMIT}, max ${MAX_MCP_SESSION_HISTORY_LIMIT}, with a 128 KiB response cap.`,
246651
+ description: `Read one bounded visible transcript page, oldest-to-newest. Use this for [@Title](session://<sessionId>) mention links: pass sessionId as the <sessionId> or the full session:// URI. Omit cursor for the newest page; nextCursor reads older entries. Defaults to ${DEFAULT_MCP_SESSION_HISTORY_LIMIT}, max ${MAX_MCP_SESSION_HISTORY_LIMIT}, with a 128 KiB response cap.`,
248656
246652
  inputSchema: SessionHistoryToolInputSchema
248657
246653
  }, async (args2) => {
248658
246654
  try {
@@ -248661,241 +246657,6 @@ ${lines2.join("\n")}` : ""}${suffix}`);
248661
246657
  return mcpErrorResult(error2);
248662
246658
  }
248663
246659
  });
248664
- const taskListTool = server.registerTool(TASK_LIST_TOOL_NAME, {
248665
- title: "List Lody tasks",
248666
- description: "Find tasks in this workspace by status, owner, agent, or title, and get their ids so you can read or update one. Returns list summaries only \u2014 call lody_task_get for a task description, comments, or links.",
248667
- inputSchema: TaskListToolInputSchema
248668
- }, async (args2) => {
248669
- try {
248670
- const ctx = getSessionContext();
248671
- const auth = getAuthContextOrThrow$1("mcp");
248672
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248673
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248674
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248675
- const filter2 = buildTaskListFilter(args2, auth.userId);
248676
- const page = await listTasksFromIndex(manager, workspace.id, filter2);
248677
- return jsonTextResult({
248678
- ok: true,
248679
- tasks: page.rows.map(summarizeTaskIndexRowForMcp),
248680
- ...page.matched > page.rows.length ? {
248681
- matched: page.matched
248682
- } : {}
248683
- });
248684
- });
248685
- } catch (error2) {
248686
- return mcpErrorResult(error2);
248687
- }
248688
- });
248689
- const taskGetTool = server.registerTool(TASK_GET_TOOL_NAME, {
248690
- title: "Read a Lody task",
248691
- description: "Read a task: title, status, owner, description body, linked sessions and pull requests, and recent comments. Read before editing the body so your edit matches the current text.",
248692
- inputSchema: TaskGetToolInputSchema
248693
- }, async (args2) => {
248694
- try {
248695
- const ctx = getSessionContext();
248696
- const auth = getAuthContextOrThrow$1("mcp");
248697
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248698
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248699
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248700
- const snapshot = await readTask(manager, args2.taskId);
248701
- if (!snapshot) {
248702
- return jsonTextResult({
248703
- ok: false,
248704
- error: makeLodyError("TASK_NOT_FOUND", `Task not found: ${args2.taskId}`, false)
248705
- }, true);
248706
- }
248707
- return jsonTextResult({
248708
- ok: true,
248709
- task: summarizeTaskForMcp(snapshot)
248710
- });
248711
- });
248712
- } catch (error2) {
248713
- return mcpErrorResult(error2);
248714
- }
248715
- });
248716
- const taskCreateTool = server.registerTool(TASK_CREATE_TOOL_NAME, {
248717
- title: "Create a Lody task",
248718
- description: "Create a task now, when the user asked in this conversation to record one. For follow-up work you noticed yourself, use lody_task_propose instead so the user decides. The task is created immediately and attributed to you; it is never started automatically, because only a person can entrust a task to an agent.",
248719
- inputSchema: TaskCreateToolInputSchema
248720
- }, async (args2) => {
248721
- try {
248722
- const ctx = getSessionContext();
248723
- const auth = getAuthContextOrThrow$1("mcp");
248724
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248725
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248726
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248727
- const actor = await resolveTaskActor(manager, ctx.sessionId);
248728
- const snapshot = await createTaskFromAgent(manager, workspace.id, {
248729
- title: args2.title,
248730
- ...args2.body !== void 0 ? {
248731
- body: args2.body
248732
- } : {},
248733
- ...args2.status ? {
248734
- status: args2.status
248735
- } : {},
248736
- ...args2.ownerId !== void 0 ? {
248737
- ownerId: args2.ownerId
248738
- } : {},
248739
- ...args2.priority ? {
248740
- priority: args2.priority
248741
- } : {},
248742
- ...args2.labels ? {
248743
- labels: args2.labels
248744
- } : {},
248745
- ...args2.project ? {
248746
- projects: [
248747
- toTaskProjectRef(args2.project)
248748
- ]
248749
- } : {}
248750
- }, actor, auth.userId);
248751
- if (!snapshot) {
248752
- return jsonTextResult({
248753
- ok: false,
248754
- error: makeLodyError("TASK_EMPTY", "A task needs a title or a description.", false)
248755
- }, true);
248756
- }
248757
- return jsonTextResult({
248758
- ok: true,
248759
- task: summarizeTaskForMcp(snapshot)
248760
- });
248761
- });
248762
- } catch (error2) {
248763
- return mcpErrorResult(error2);
248764
- }
248765
- });
248766
- const taskProposeTool = server.registerTool(TASK_PROPOSE_TOOL_NAME, {
248767
- title: "Propose a Lody task",
248768
- description: "Suggest that work be recorded as a task, when the user asks you to note something for later or you find follow-up work outside the current scope. This does not create the task: it puts a card in this conversation that the user can confirm now or days from now. Reuse the same proposalId to update your own pending proposal instead of adding another card.",
248769
- inputSchema: TaskProposeToolInputSchema
248770
- }, async (args2) => {
248771
- try {
248772
- const ctx = getSessionContext();
248773
- const auth = getAuthContextOrThrow$1("mcp");
248774
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248775
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248776
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248777
- const sessionId = ctx.sessionId;
248778
- const actor = await resolveTaskActor(manager, sessionId);
248779
- const proposal = await publishTaskProposal(manager, sessionId, args2, actor);
248780
- return jsonTextResult({
248781
- ok: true,
248782
- proposalId: args2.proposalId,
248783
- ...proposal,
248784
- note: proposal.pending ? "The proposal is synchronized. A Tasks-enabled client can now render the confirmation card." : "This proposal was already resolved, so it was not reopened."
248785
- });
248786
- });
248787
- } catch (error2) {
248788
- return mcpErrorResult(error2);
248789
- }
248790
- });
248791
- const taskUpdateTool = server.registerTool(TASK_UPDATE_TOOL_NAME, {
248792
- title: "Update a Lody task",
248793
- description: "Change a task: status, title, priority, labels, project, and the pull request this work produced. Linking a pull request delegates completion to it: the task finishes when the pull request merges. Every change is attributed to you on the task. The description is edited separately with lody_task_edit_body. Two things stay human-only: entrusting an agent, and assigning an owner to a person (you may clear an owner).",
248794
- inputSchema: TaskUpdateToolInputSchema
248795
- }, async (args2) => {
248796
- try {
248797
- const ctx = getSessionContext();
248798
- const auth = getAuthContextOrThrow$1("mcp");
248799
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248800
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248801
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248802
- const sessionId = ctx.sessionId;
248803
- const actor = await resolveTaskActor(manager, sessionId);
248804
- const snapshot = await applyAgentTaskUpdate(manager, workspace.id, args2.taskId, buildTaskUpdateInput(args2, sessionId), actor);
248805
- if (!snapshot) {
248806
- return jsonTextResult({
248807
- ok: false,
248808
- error: makeLodyError("TASK_NOT_FOUND", `Task not found: ${args2.taskId}`, false)
248809
- }, true);
248810
- }
248811
- return jsonTextResult({
248812
- ok: true,
248813
- task: summarizeTaskForMcp(snapshot)
248814
- });
248815
- });
248816
- } catch (error2) {
248817
- return mcpErrorResult(error2);
248818
- }
248819
- });
248820
- const taskEditBodyTool = server.registerTool(TASK_EDIT_BODY_TOOL_NAME, {
248821
- title: "Edit a Lody task description",
248822
- description: "Replace an exact snippet of a task description, the same way a file edit works. oldString must match the current body exactly; an empty oldString appends. On a mismatch the current body is returned so you can retry. Every edit is attributed to you and recorded on the task, so edit directly rather than asking for permission first.",
248823
- inputSchema: TaskEditBodyToolInputSchema
248824
- }, async (args2) => {
248825
- try {
248826
- const ctx = getSessionContext();
248827
- const auth = getAuthContextOrThrow$1("mcp");
248828
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248829
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248830
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248831
- const sessionId = ctx.sessionId;
248832
- const actor = await resolveTaskActor(manager, sessionId);
248833
- const result = await applyAgentTaskBodyEdit(manager, workspace.id, args2.taskId, {
248834
- oldString: args2.oldString,
248835
- newString: args2.newString
248836
- }, actor, sessionId);
248837
- if (!result.ok) {
248838
- if (result.code === "NO_MATCH") {
248839
- return jsonTextResult({
248840
- ok: false,
248841
- error: makeLodyError("BODY_NO_MATCH", "oldString was not found in the current task body. Retry against currentBody.", true),
248842
- ...summarizeTaskBodyForMcp(result.body, "currentBody")
248843
- }, true);
248844
- }
248845
- if (result.code === "AMBIGUOUS_MATCH") {
248846
- return jsonTextResult({
248847
- ok: false,
248848
- error: makeLodyError("BODY_AMBIGUOUS_MATCH", `oldString matches ${result.occurrences} places; include more context to make it unique.`, true)
248849
- }, true);
248850
- }
248851
- return jsonTextResult({
248852
- ok: false,
248853
- error: makeLodyError("TASK_NOT_FOUND", `Task not found: ${args2.taskId}`, false)
248854
- }, true);
248855
- }
248856
- return jsonTextResult({
248857
- ok: true,
248858
- added: result.added,
248859
- removed: result.removed,
248860
- task: summarizeTaskForMcp(result.snapshot)
248861
- });
248862
- });
248863
- } catch (error2) {
248864
- return mcpErrorResult(error2);
248865
- }
248866
- });
248867
- const taskCommentTool = server.registerTool(TASK_COMMENT_TOOL_NAME, {
248868
- title: "Comment on a Lody task",
248869
- description: "Add a comment to a task thread \u2014 a progress note, a summary of what you did, or a question for the owner. Comments are coordination, not execution: posting one never starts work.",
248870
- inputSchema: TaskCommentToolInputSchema
248871
- }, async (args2) => {
248872
- try {
248873
- const ctx = getSessionContext();
248874
- const auth = getAuthContextOrThrow$1("mcp");
248875
- const workspace = await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
248876
- return await withWorkspaceManager$1(auth, workspace, "mcp", async (manager) => {
248877
- await assertInvokingTurnTaskToolsEnabled(manager, ctx.sessionId);
248878
- const sessionId = ctx.sessionId;
248879
- const actor = await resolveTaskActor(manager, sessionId);
248880
- const appended = await appendAgentTaskComment(manager, workspace.id, args2.taskId, {
248881
- body: args2.body,
248882
- originSessionId: sessionId
248883
- }, actor);
248884
- if (!appended) {
248885
- return jsonTextResult({
248886
- ok: false,
248887
- error: makeLodyError("TASK_NOT_FOUND", `Task not found: ${args2.taskId}`, false)
248888
- }, true);
248889
- }
248890
- return jsonTextResult({
248891
- ok: true,
248892
- taskId: args2.taskId
248893
- });
248894
- });
248895
- } catch (error2) {
248896
- return mcpErrorResult(error2);
248897
- }
248898
- });
248899
246660
  server.registerTool(REVIEW_SUBMIT_TOOL_NAME, {
248900
246661
  title: "Submit a code review",
248901
246662
  description: "Report the result of reviewing a branch. Call this exactly once per review round. Only a session acting as a review agent can use it.",
@@ -248970,27 +246731,10 @@ ${lines2.join("\n")}` : ""}${suffix}`);
248970
246731
  return mcpErrorResult(error2);
248971
246732
  }
248972
246733
  });
248973
- if (config2.taskToolsEnabled !== true) {
248974
- for (const tool of [
248975
- taskImageUploadTool,
248976
- taskListTool,
248977
- taskGetTool,
248978
- taskCreateTool,
248979
- taskProposeTool,
248980
- taskUpdateTool,
248981
- taskEditBodyTool,
248982
- taskCommentTool
248983
- ]) {
248984
- tool.disable();
248985
- }
248986
- }
248987
246734
  return server;
248988
246735
  }
248989
246736
  async function runLodyMcpServer() {
248990
- const context2 = getSessionContext();
248991
- await buildLodyMcpServer({
248992
- taskToolsEnabled: context2.taskToolsEnabled
248993
- }).connect(new StdioServerTransport());
246737
+ await buildLodyMcpServer().connect(new StdioServerTransport());
248994
246738
  }
248995
246739
  var RequestError = class extends Error {
248996
246740
  constructor(message, options) {
@@ -250537,9 +248281,8 @@ data:
250537
248281
  const rawSessionId = singleHeader(req, MCP_HTTP_SESSION_ID_HEADER);
250538
248282
  const workspaceId = singleHeader(req, MCP_HTTP_WORKSPACE_ID_HEADER);
250539
248283
  const machineId = singleHeader(req, MCP_HTTP_MACHINE_ID_HEADER);
250540
- const taskToolsEnabled = singleHeader(req, MCP_HTTP_TASK_TOOLS_ENABLED_HEADER);
250541
248284
  const workdirB64 = singleHeader(req, MCP_HTTP_WORKDIR_B64_HEADER);
250542
- if (!rawSessionId || !workspaceId || !machineId || taskToolsEnabled !== "0" && taskToolsEnabled !== "1" || !workdirB64) {
248285
+ if (!rawSessionId || !workspaceId || !machineId || !workdirB64) {
250543
248286
  return null;
250544
248287
  }
250545
248288
  const sessionId = SessionIdSchema$1.safeParse(rawSessionId);
@@ -250559,7 +248302,6 @@ data:
250559
248302
  sessionId: sessionId.data,
250560
248303
  workspaceId,
250561
248304
  machineId,
250562
- taskToolsEnabled: taskToolsEnabled === "1",
250563
248305
  workdir,
250564
248306
  localControlSocketPath: getLocalControlSocketPath()
250565
248307
  };
@@ -250617,9 +248359,7 @@ data:
250617
248359
  reject(res, 400, "Missing or invalid Lody MCP session context headers");
250618
248360
  return;
250619
248361
  }
250620
- const server = buildLodyMcpServer({
250621
- taskToolsEnabled: context2.taskToolsEnabled
250622
- });
248362
+ const server = buildLodyMcpServer();
250623
248363
  const transport = new StreamableHTTPServerTransport({
250624
248364
  sessionIdGenerator: void 0,
250625
248365
  enableJsonResponse: true