alaska-ai 0.1.30 → 0.1.32

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.
Files changed (41) hide show
  1. package/dist/adapters/slack.d.ts +3 -0
  2. package/dist/adapters/slack.js +98 -12
  3. package/dist/adapters/slack.js.map +1 -1
  4. package/dist/backends/claude.js +10 -2
  5. package/dist/backends/claude.js.map +1 -1
  6. package/dist/backends/codex-app-server.d.ts +45 -0
  7. package/dist/backends/codex-app-server.js +593 -0
  8. package/dist/backends/codex-app-server.js.map +1 -0
  9. package/dist/backends/codex.js +13 -5
  10. package/dist/backends/codex.js.map +1 -1
  11. package/dist/backends/process-utils.d.ts +11 -0
  12. package/dist/backends/process-utils.js +68 -0
  13. package/dist/backends/process-utils.js.map +1 -0
  14. package/dist/gateway.d.ts +73 -0
  15. package/dist/gateway.js +428 -0
  16. package/dist/gateway.js.map +1 -0
  17. package/dist/mcp/callbacks.d.ts +3 -1
  18. package/dist/mcp/callbacks.js +13 -2
  19. package/dist/mcp/callbacks.js.map +1 -1
  20. package/dist/router.d.ts +1 -0
  21. package/dist/router.js +22 -4
  22. package/dist/router.js.map +1 -1
  23. package/dist/runtime/gateway-worker.d.ts +39 -0
  24. package/dist/runtime/gateway-worker.js +257 -0
  25. package/dist/runtime/gateway-worker.js.map +1 -0
  26. package/dist/runtime/inline-codex-runtime.d.ts +45 -0
  27. package/dist/runtime/inline-codex-runtime.js +512 -0
  28. package/dist/runtime/inline-codex-runtime.js.map +1 -0
  29. package/dist/runtime/run-coordinator.d.ts +16 -0
  30. package/dist/runtime/run-coordinator.js +106 -0
  31. package/dist/runtime/run-coordinator.js.map +1 -0
  32. package/dist/runtime/runner.d.ts +28 -0
  33. package/dist/runtime/runner.js +2 -0
  34. package/dist/runtime/runner.js.map +1 -0
  35. package/dist/runtime/session-service.d.ts +16 -0
  36. package/dist/runtime/session-service.js +65 -0
  37. package/dist/runtime/session-service.js.map +1 -0
  38. package/dist/scheduler.js +10 -3
  39. package/dist/scheduler.js.map +1 -1
  40. package/dist/types/events.d.ts +3 -0
  41. package/package.json +1 -1
@@ -96,6 +96,9 @@ export declare class SlackAdapter {
96
96
  private trackPermissionAck;
97
97
  /** Remove :eyes: from all tracked permission ack messages for a thread. */
98
98
  private cleanupPermissionAcks;
99
+ private stripAssistantTexts;
100
+ private logSuppressedError;
101
+ private logSuppressedCommandFailure;
99
102
  private detectGmailToolDrift;
100
103
  private withGmailRecoveryHint;
101
104
  private hasGmailMutationClaim;
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process';
11
11
  import { App } from '@slack/bolt';
12
12
  import { splitText, downloadAndStageFile, markdownToSlackMrkdwn } from '../utils.js';
13
13
  import { resolvePermission, resolveUserQuestion, hasPendingQuestion, resolveQuestionByThread } from '../mcp/ipc-server.js';
14
- import { clearPostMessageFlag, wasPostMessageCalled, clearScheduleFlag, wasScheduleCreated, clearGmailActionFlag, wasGmailActionCalled, getGmailActions, getGmailActionReceipts, } from '../mcp/callbacks.js';
14
+ import { clearPostMessageFlag, getPostMessageTexts, wasPostMessageCalled, clearScheduleFlag, wasScheduleCreated, clearGmailActionFlag, wasGmailActionCalled, getGmailActions, getGmailActionReceipts, } from '../mcp/callbacks.js';
15
15
  import { requireSandboxRoot, resolveWithinSandbox, validateSandboxRoot } from '../sandbox-policy.js';
16
16
  import { defaultAsyncErrorSink, withAsyncErrorPropagation, } from '../async-callback.js';
17
17
  import { buildThreadDeployUrl, isValidThreadId, normalizeThreadId, THREAD_DEPLOY_BASE_URL, THREAD_WEB_MODE_MARKER, } from '../lib/thread-id.js';
@@ -781,6 +781,18 @@ export class SlackAdapter {
781
781
  await this.removeReactSeen(ack.channel, ack.ts, client);
782
782
  }
783
783
  }
784
+ stripAssistantTexts(events, predicate) {
785
+ return events.filter((event) => event.type !== 'assistant_text' || !predicate(event.text));
786
+ }
787
+ logSuppressedError(threadTs, message) {
788
+ console.warn(`[slack] internal error for thread ${threadTs}: ${message}`);
789
+ }
790
+ logSuppressedCommandFailure(threadTs, event) {
791
+ const command = event.command.trim() || '(unknown command)';
792
+ const output = event.output.trim() || '(no output captured)';
793
+ const clipped = output.length > 1200 ? `${output.slice(0, 1200)}\n... (truncated)` : output;
794
+ console.warn(`[slack] internal command failure for thread ${threadTs}: exit=${event.exitCode} command=${command}\n${clipped}`);
795
+ }
784
796
  detectGmailToolDrift(events) {
785
797
  for (const event of events) {
786
798
  const raw = event.type === 'assistant_text'
@@ -808,7 +820,12 @@ export class SlackAdapter {
808
820
  ...result,
809
821
  events: [
810
822
  ...result.events,
811
- { type: 'error', message: GMAIL_RECOVERY_HINT },
823
+ {
824
+ type: 'error',
825
+ message: GMAIL_RECOVERY_HINT,
826
+ visibility: 'blocking',
827
+ userMessage: GMAIL_RECOVERY_HINT,
828
+ },
812
829
  ],
813
830
  };
814
831
  }
@@ -839,14 +856,27 @@ export class SlackAdapter {
839
856
  }
840
857
  const actions = getGmailActions(threadTs);
841
858
  const actionLabel = actions.length > 0 ? actions.join(', ') : '(none)';
859
+ const sanitizedEvents = this.stripAssistantTexts(result.events, (text) => {
860
+ const normalized = text.replace(/\s+/g, ' ').trim();
861
+ if (!normalized)
862
+ return false;
863
+ if (!GMAIL_MUTATION_CLAIM_RE.test(normalized))
864
+ return false;
865
+ return !GMAIL_NEGATION_RE.test(normalized);
866
+ });
842
867
  return {
843
868
  ...result,
844
869
  events: [
845
- ...result.events,
870
+ ...sanitizedEvents,
871
+ {
872
+ type: 'assistant_text',
873
+ text: 'No mailbox changes were applied in this turn because no gmail_* tool executed.',
874
+ },
846
875
  {
847
876
  type: 'error',
848
877
  message: 'No gmail_* tool was executed in this turn, so no mailbox changes were applied. ' +
849
878
  `Observed actions: ${actionLabel}. Ask me to run gmail_prepare_delete/gmail_confirm_action or gmail_prepare_delete_query/gmail_confirm_action explicitly.`,
879
+ visibility: 'debug',
850
880
  },
851
881
  ],
852
882
  };
@@ -870,7 +900,7 @@ export class SlackAdapter {
870
900
  ...result,
871
901
  events: [
872
902
  ...result.events,
873
- { type: 'error', message },
903
+ { type: 'assistant_text', text: message },
874
904
  ],
875
905
  };
876
906
  }
@@ -904,16 +934,29 @@ export class SlackAdapter {
904
934
  return result;
905
935
  if (!this.hasThreadWebCompletionClaim(result.events))
906
936
  return result;
937
+ const withoutCompletionClaims = this.stripAssistantTexts(result.events, (text) => {
938
+ const normalized = text.replace(/\s+/g, ' ').trim();
939
+ if (!normalized)
940
+ return false;
941
+ if (THREAD_WEB_COMPLETION_CLAIM_RE.test(normalized))
942
+ return true;
943
+ return normalized.includes(THREAD_DEPLOY_BASE_URL);
944
+ });
907
945
  const deployUrl = buildThreadDeployUrl(threadTs);
908
946
  if (!deployUrl) {
909
947
  return {
910
948
  ...result,
911
949
  events: [
912
- ...result.events,
950
+ ...withoutCompletionClaims,
951
+ {
952
+ type: 'assistant_text',
953
+ text: 'Thread web publish could not be verified as complete.',
954
+ },
913
955
  {
914
956
  type: 'error',
915
957
  message: 'Thread deploy validation failed: invalid thread ID format. ' +
916
958
  'Use Slack thread_ts normalized by "." -> "-", and verify through lib/thread-id.ts.',
959
+ visibility: 'debug',
917
960
  },
918
961
  ],
919
962
  };
@@ -931,12 +974,17 @@ export class SlackAdapter {
931
974
  return {
932
975
  ...result,
933
976
  events: [
934
- ...result.events,
977
+ ...withoutCompletionClaims,
978
+ {
979
+ type: 'assistant_text',
980
+ text: 'Thread web publish is not complete yet.',
981
+ },
935
982
  {
936
983
  type: 'error',
937
984
  message: 'Thread web publish is not complete: missing ' +
938
985
  `${missing.join(' and ')}. ` +
939
986
  'Finish the publish flow before declaring deployment complete.',
987
+ visibility: 'debug',
940
988
  },
941
989
  ],
942
990
  };
@@ -1489,19 +1537,30 @@ export class SlackAdapter {
1489
1537
  }
1490
1538
  return true;
1491
1539
  });
1492
- // If Claude used post_message during this turn, suppress assistant_text
1493
- // (Claude already communicated directly). Otherwise, render only the last
1494
- // assistant_text block as a fallback summary.
1540
+ // If post_message was used during this turn, suppress only duplicate
1541
+ // assistant_text content. This preserves explicit progress updates while
1542
+ // still delivering a distinct final answer.
1495
1543
  const postMessageUsed = wasPostMessageCalled(threadTs);
1544
+ const postMessageTexts = postMessageUsed
1545
+ ? new Set(getPostMessageTexts(threadTs)
1546
+ .map((text) => text.trim())
1547
+ .filter(Boolean))
1548
+ : new Set();
1496
1549
  const assistantTexts = deduped.filter(e => e.type === 'assistant_text');
1497
1550
  const lastAssistantText = assistantTexts.length > 0
1498
1551
  ? assistantTexts[assistantTexts.length - 1]
1499
1552
  : null;
1553
+ let renderedUserMessage = false;
1554
+ let sawSuppressedCommandFailure = false;
1555
+ let sawSuppressedDiagnostic = false;
1556
+ const summaryMessages = new Set();
1500
1557
  for (const event of deduped) {
1501
1558
  switch (event.type) {
1502
1559
  case 'assistant_text':
1503
- if (!postMessageUsed && event === lastAssistantText) {
1560
+ if (event === lastAssistantText &&
1561
+ (!postMessageUsed || !postMessageTexts.has(event.text.trim()))) {
1504
1562
  await this.postText(channelId, threadTs, event.text, client);
1563
+ renderedUserMessage = true;
1505
1564
  }
1506
1565
  break;
1507
1566
  case 'permission_denied':
@@ -1514,13 +1573,26 @@ export class SlackAdapter {
1514
1573
  else {
1515
1574
  await this.postPermissionPrompt(channelId, threadTs, event, client);
1516
1575
  }
1576
+ renderedUserMessage = true;
1517
1577
  break;
1518
1578
  case 'error':
1519
- await this.postError(channelId, threadTs, event.message, client);
1579
+ this.logSuppressedError(threadTs, event.message);
1580
+ if (event.visibility === 'blocking') {
1581
+ await this.postError(channelId, threadTs, event.userMessage ?? event.message, client);
1582
+ renderedUserMessage = true;
1583
+ }
1584
+ else if (event.visibility === 'summary') {
1585
+ summaryMessages.add(event.userMessage ?? 'The task did not complete. Details were recorded in the debug logs.');
1586
+ sawSuppressedDiagnostic = true;
1587
+ }
1588
+ else {
1589
+ sawSuppressedDiagnostic = true;
1590
+ }
1520
1591
  break;
1521
1592
  case 'command_execution':
1522
1593
  if (event.exitCode !== 0) {
1523
- await this.postCommandFailure(channelId, threadTs, event, client);
1594
+ this.logSuppressedCommandFailure(threadTs, event);
1595
+ sawSuppressedCommandFailure = true;
1524
1596
  }
1525
1597
  break;
1526
1598
  // Other event types (tool_use, tool_result, etc.)
@@ -1529,6 +1601,20 @@ export class SlackAdapter {
1529
1601
  break;
1530
1602
  }
1531
1603
  }
1604
+ if (renderedUserMessage) {
1605
+ return;
1606
+ }
1607
+ if (summaryMessages.size > 0) {
1608
+ const summaries = [...summaryMessages];
1609
+ const message = summaries.length === 1
1610
+ ? summaries[0]
1611
+ : summaries.map((item) => `- ${item}`).join('\n');
1612
+ await this.postText(channelId, threadTs, message, client);
1613
+ return;
1614
+ }
1615
+ if (sawSuppressedCommandFailure || sawSuppressedDiagnostic) {
1616
+ await this.postText(channelId, threadTs, 'The task hit internal errors and did not produce a user-facing resolution. Details were recorded in the debug logs.', client);
1617
+ }
1532
1618
  }
1533
1619
  /** Post text response, splitting if it exceeds Slack's limit. */
1534
1620
  async postText(channelId, threadTs, text, client) {