dorkos 0.17.0 → 0.17.2

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.
@@ -15,7 +15,7 @@
15
15
  if (dark) document.documentElement.classList.add('dark');
16
16
  })();
17
17
  </script>
18
- <script type="module" crossorigin src="/assets/index-KNXnL08A.js"></script>
18
+ <script type="module" crossorigin src="/assets/index-BktypfRN.js"></script>
19
19
  <link rel="stylesheet" crossorigin href="/assets/index-1b_G52ou.css">
20
20
  </head>
21
21
  <body>
@@ -68656,6 +68656,9 @@ var init_test_mode_runtime = __esm({
68656
68656
  async getSessionETag(_projectDir, _id) {
68657
68657
  return null;
68658
68658
  }
68659
+ async getLastMessageIds(_sessionId) {
68660
+ return null;
68661
+ }
68659
68662
  async readFromOffset(_projectDir, _id, _offset) {
68660
68663
  return { content: "", newOffset: 0 };
68661
68664
  }
@@ -68892,7 +68895,8 @@ var UpdateSessionRequestSchema = z.object({
68892
68895
  var SendMessageRequestSchema = z.object({
68893
68896
  content: z.string().min(1, "content is required"),
68894
68897
  cwd: z.string().optional(),
68895
- correlationId: z.string().uuid().optional()
68898
+ correlationId: z.string().uuid().optional(),
68899
+ clientMessageId: z.string().optional()
68896
68900
  }).openapi("SendMessageRequest");
68897
68901
  var ApprovalRequestSchema = z.object({
68898
68902
  toolCallId: z.string()
@@ -70868,20 +70872,27 @@ router.post("/:id/messages", async (req, res) => {
70868
70872
  initSSEStream(res);
70869
70873
  try {
70870
70874
  for await (const event of runtime.sendMessage(sessionId, content3, { cwd })) {
70871
- await sendSSEEvent(res, event);
70872
70875
  if (event.type === "done") {
70873
70876
  const actualInternalId = runtime.getInternalSessionId(sessionId);
70877
+ const lookupId = actualInternalId ?? sessionId;
70878
+ const lastMsgIds = await runtime.getLastMessageIds(lookupId);
70879
+ const donePayload = {
70880
+ ...event.data && typeof event.data === "object" ? event.data : {}
70881
+ };
70874
70882
  if (actualInternalId && actualInternalId !== sessionId) {
70875
70883
  logger.debug("[POST /messages] session ID remapped", {
70876
70884
  sessionId,
70877
70885
  internalId: actualInternalId
70878
70886
  });
70879
- await sendSSEEvent(res, {
70880
- type: "done",
70881
- data: { sessionId: actualInternalId }
70882
- });
70887
+ donePayload.sessionId = actualInternalId;
70888
+ }
70889
+ if (lastMsgIds) {
70890
+ donePayload.messageIds = lastMsgIds;
70883
70891
  }
70892
+ await sendSSEEvent(res, { type: "done", data: donePayload });
70893
+ continue;
70884
70894
  }
70895
+ await sendSSEEvent(res, event);
70885
70896
  }
70886
70897
  } catch (err) {
70887
70898
  logger.warn("[POST /messages] SSE stream error", {
@@ -71060,7 +71071,7 @@ var SERVER_VERSION = resolveVersion();
71060
71071
  var IS_DEV_BUILD = checkDevBuild(SERVER_VERSION);
71061
71072
  function resolveVersion() {
71062
71073
  if (env.DORKOS_VERSION_OVERRIDE) return env.DORKOS_VERSION_OVERRIDE;
71063
- if (true) return "0.17.0";
71074
+ if (true) return "0.17.2";
71064
71075
  const pkgPath = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "../../package.json");
71065
71076
  return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
71066
71077
  }
@@ -74395,6 +74406,24 @@ function parseTranscript(lines) {
74395
74406
  };
74396
74407
  parts.push(toolCallPart);
74397
74408
  toolCallPartMap.set(block.id, toolCallPart);
74409
+ } else if (block.type === "error") {
74410
+ parts.push({
74411
+ type: "error",
74412
+ message: block.message ?? "",
74413
+ category: block.category ?? void 0,
74414
+ details: block.details ?? void 0
74415
+ });
74416
+ } else if (block.type === "subagent") {
74417
+ parts.push({
74418
+ type: "subagent",
74419
+ taskId: block.task_id ?? block.id ?? "",
74420
+ description: block.description ?? "",
74421
+ status: block.status ?? "running",
74422
+ toolUses: block.tool_uses,
74423
+ lastToolName: block.last_tool_name,
74424
+ durationMs: block.duration_ms,
74425
+ summary: block.summary
74426
+ });
74398
74427
  }
74399
74428
  }
74400
74429
  if (parts.length === 0) continue;
@@ -74409,7 +74438,29 @@ function parseTranscript(lines) {
74409
74438
  });
74410
74439
  }
74411
74440
  }
74412
- return messages;
74441
+ return mergeConsecutiveAssistantMessages(messages);
74442
+ }
74443
+ function mergeConsecutiveAssistantMessages(messages) {
74444
+ const merged = [];
74445
+ for (const msg of messages) {
74446
+ const prev = merged[merged.length - 1];
74447
+ if (prev && prev.role === "assistant" && msg.role === "assistant") {
74448
+ prev.id = msg.id;
74449
+ prev.parts = [...prev.parts ?? [], ...msg.parts ?? []];
74450
+ if (msg.content) {
74451
+ prev.content = prev.content ? prev.content + "\n" + msg.content : msg.content;
74452
+ }
74453
+ if (msg.toolCalls) {
74454
+ prev.toolCalls = [...prev.toolCalls ?? [], ...msg.toolCalls];
74455
+ }
74456
+ if (msg.timestamp) prev.timestamp = msg.timestamp;
74457
+ } else {
74458
+ const copy = { ...msg };
74459
+ if (copy.parts) copy.parts = [...copy.parts];
74460
+ merged.push(copy);
74461
+ }
74462
+ }
74463
+ return merged;
74413
74464
  }
74414
74465
 
74415
74466
  // ../../apps/server/src/services/runtimes/claude-code/task-reader.ts
@@ -78358,6 +78409,31 @@ var ClaudeCodeRuntime = class _ClaudeCodeRuntime {
78358
78409
  async getSessionETag(projectDir, sessionId) {
78359
78410
  return this.transcriptReader.getTranscriptETag(projectDir, sessionId);
78360
78411
  }
78412
+ /** @inheritdoc */
78413
+ async getLastMessageIds(sessionId) {
78414
+ try {
78415
+ const session = this.findSession(sessionId);
78416
+ const projectDir = session?.cwd ?? this.cwd;
78417
+ const messages = await this.transcriptReader.readTranscript(projectDir, sessionId);
78418
+ if (!messages.length) return null;
78419
+ let lastUser = null;
78420
+ let lastAssistant = null;
78421
+ for (let i2 = messages.length - 1; i2 >= 0; i2--) {
78422
+ const m3 = messages[i2];
78423
+ if (!lastAssistant && m3.role === "assistant") lastAssistant = m3.id;
78424
+ if (!lastUser && m3.role === "user") lastUser = m3.id;
78425
+ if (lastUser && lastAssistant) break;
78426
+ }
78427
+ if (!lastUser || !lastAssistant) return null;
78428
+ return { user: lastUser, assistant: lastAssistant };
78429
+ } catch (err) {
78430
+ logger.warn("[getLastMessageIds] failed to read transcript", {
78431
+ sessionId,
78432
+ error: err instanceof Error ? err.message : String(err)
78433
+ });
78434
+ return null;
78435
+ }
78436
+ }
78361
78437
  /** Read new content from a session transcript starting at a byte offset. */
78362
78438
  async readFromOffset(projectDir, sessionId, offset) {
78363
78439
  return this.transcriptReader.readFromOffset(projectDir, sessionId, offset);
@@ -102565,6 +102641,26 @@ function clearCaches() {
102565
102641
  userNameCache.clear();
102566
102642
  channelNameCache.clear();
102567
102643
  }
102644
+ function removeQueuedReaction(client, channelId, messageTs, pendingReactions, wasQueued, logger3) {
102645
+ if (!wasQueued)
102646
+ return;
102647
+ if (pendingReactions) {
102648
+ const queue2 = pendingReactions.get(channelId);
102649
+ if (queue2) {
102650
+ const idx = queue2.indexOf(messageTs);
102651
+ if (idx !== -1)
102652
+ queue2.splice(idx, 1);
102653
+ if (queue2.length === 0)
102654
+ pendingReactions.delete(channelId);
102655
+ }
102656
+ }
102657
+ void client.reactions.remove({ channel: channelId, name: "hourglass_flowing_sand", timestamp: messageTs }).catch((err) => {
102658
+ const msg = err instanceof Error ? err.message : String(err);
102659
+ if (!msg.includes("no_reaction")) {
102660
+ logger3.warn(`inbound: failed to remove queued typing reaction from ${channelId}:${messageTs}: ${msg}`);
102661
+ }
102662
+ });
102663
+ }
102568
102664
  async function handleInboundMessage2(event, client, relay, botUserId, callbacks, logger3 = noopLogger, typingIndicator = "none", pendingReactions) {
102569
102665
  if (event.user === botUserId) {
102570
102666
  logger3.debug(`inbound skipped: echo (own user ${botUserId})`);
@@ -102585,6 +102681,30 @@ async function handleInboundMessage2(event, client, relay, botUserId, callbacks,
102585
102681
  const isGroup = isGroupChannel(event.channel);
102586
102682
  const subject = buildSubject2(event.channel, isGroup);
102587
102683
  const content3 = event.text.slice(0, MAX_CONTENT_LENGTH2);
102684
+ let reactionQueued = false;
102685
+ if (typingIndicator === "reaction") {
102686
+ if (pendingReactions) {
102687
+ const queue2 = pendingReactions.get(event.channel) ?? [];
102688
+ queue2.push(event.ts);
102689
+ pendingReactions.set(event.channel, queue2);
102690
+ reactionQueued = true;
102691
+ }
102692
+ client.reactions.add({ channel: event.channel, name: "hourglass_flowing_sand", timestamp: event.ts }).then(() => {
102693
+ logger3.debug(`inbound: added typing reaction to ${event.channel}:${event.ts}`);
102694
+ }).catch((err) => {
102695
+ if (pendingReactions) {
102696
+ const queue2 = pendingReactions.get(event.channel);
102697
+ if (queue2) {
102698
+ const idx = queue2.indexOf(event.ts);
102699
+ if (idx !== -1)
102700
+ queue2.splice(idx, 1);
102701
+ if (queue2.length === 0)
102702
+ pendingReactions.delete(event.channel);
102703
+ }
102704
+ }
102705
+ logger3.warn(`inbound: failed to add typing reaction to ${event.channel}:${event.ts}: ${err instanceof Error ? err.message : String(err)}`);
102706
+ });
102707
+ }
102588
102708
  const senderName = event.user ? await resolveUserName(client, event.user) : "unknown";
102589
102709
  const channelName = isGroup ? await resolveChannelName(client, event.channel) : void 0;
102590
102710
  const payload = {
@@ -102616,35 +102736,15 @@ async function handleInboundMessage2(event, client, relay, botUserId, callbacks,
102616
102736
  const reason = result2.rejected[0]?.reason ?? "unknown";
102617
102737
  callbacks.recordError(new Error(`Publish rejected: ${reason}`));
102618
102738
  logger3.warn(`inbound publish rejected for ${event.channel}: ${reason}`);
102739
+ removeQueuedReaction(client, event.channel, event.ts, pendingReactions, reactionQueued, logger3);
102619
102740
  return;
102620
102741
  }
102621
102742
  callbacks.trackInbound();
102622
102743
  logger3.debug(`inbound from ${senderName} in ${event.channel}: "${content3.slice(0, 80)}${content3.length > 80 ? "\u2026" : ""}" (${content3.length} chars) \u2192 ${subject}`);
102623
- if (typingIndicator === "reaction") {
102624
- if (pendingReactions) {
102625
- const queue2 = pendingReactions.get(event.channel) ?? [];
102626
- queue2.push(event.ts);
102627
- pendingReactions.set(event.channel, queue2);
102628
- }
102629
- client.reactions.add({ channel: event.channel, name: "hourglass_flowing_sand", timestamp: event.ts }).then(() => {
102630
- logger3.debug(`inbound: added typing reaction to ${event.channel}:${event.ts}`);
102631
- }).catch((err) => {
102632
- if (pendingReactions) {
102633
- const queue2 = pendingReactions.get(event.channel);
102634
- if (queue2) {
102635
- const idx = queue2.indexOf(event.ts);
102636
- if (idx !== -1)
102637
- queue2.splice(idx, 1);
102638
- if (queue2.length === 0)
102639
- pendingReactions.delete(event.channel);
102640
- }
102641
- }
102642
- logger3.warn(`inbound: failed to add typing reaction to ${event.channel}:${event.ts}: ${err instanceof Error ? err.message : String(err)}`);
102643
- });
102644
- }
102645
102744
  } catch (err) {
102646
102745
  callbacks.recordError(err);
102647
102746
  logger3.warn(`inbound publish failed for ${event.channel}:`, err instanceof Error ? err.message : String(err));
102747
+ removeQueuedReaction(client, event.channel, event.ts, pendingReactions, reactionQueued, logger3);
102648
102748
  }
102649
102749
  }
102650
102750
 
@@ -103038,6 +103138,9 @@ async function deliverMessage2(opts) {
103038
103138
  for (const [key, stream] of streamState) {
103039
103139
  if (startTime - stream.startedAt > STREAM_TTL_MS) {
103040
103140
  streamState.delete(key);
103141
+ if (client) {
103142
+ removePendingReaction(client, stream.channelId, opts.typingIndicator, pendingReactions, logger3);
103143
+ }
103041
103144
  logger3.warn(`stream: reaped orphaned stream for ${key} (age: ${Math.round((startTime - stream.startedAt) / 1e3)}s)`);
103042
103145
  }
103043
103146
  }