@buildautomaton/cli 0.1.95 → 0.1.97

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/cli.js CHANGED
@@ -23770,6 +23770,7 @@ import os from "node:os";
23770
23770
  var INDEX_WORK_YIELD_EVERY, INDEX_DIR, INDEX_HASH_LEN;
23771
23771
  var init_constants = __esm({
23772
23772
  "../bridge/src/files/index/constants.ts"() {
23773
+ "use strict";
23773
23774
  INDEX_WORK_YIELD_EVERY = 128;
23774
23775
  INDEX_DIR = path3.join(os.homedir(), ".buildautomaton");
23775
23776
  INDEX_HASH_LEN = 16;
@@ -24124,6 +24125,7 @@ function isCliSqliteLockError(e) {
24124
24125
  var CliSqliteInterrupted;
24125
24126
  var init_sqlite_errors = __esm({
24126
24127
  "../bridge/src/sqlite/sqlite-errors.ts"() {
24128
+ "use strict";
24127
24129
  CliSqliteInterrupted = class extends Error {
24128
24130
  name = "CliSqliteInterrupted";
24129
24131
  constructor() {
@@ -24234,6 +24236,7 @@ function maybeLogCodeNavCacheWorkerError(message) {
24234
24236
  var diagnosticSink, lastDiagnosticKey;
24235
24237
  var init_code_nav_cache_log = __esm({
24236
24238
  "../bridge/src/sqlite/code-nav-cache/code-nav-cache-log.ts"() {
24239
+ "use strict";
24237
24240
  init_log();
24238
24241
  init_sqlite_errors();
24239
24242
  init_sqlite_lock_path();
@@ -30369,7 +30372,7 @@ var {
30369
30372
  } = import_index.default;
30370
30373
 
30371
30374
  // src/cli-version.ts
30372
- var CLI_VERSION = "0.1.95".length > 0 ? "0.1.95" : "0.0.0-dev";
30375
+ var CLI_VERSION = "0.1.97".length > 0 ? "0.1.97" : "0.0.0-dev";
30373
30376
 
30374
30377
  // src/cli/defaults.ts
30375
30378
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -30673,7 +30676,7 @@ function formatSpawnError(err, command) {
30673
30676
  }
30674
30677
 
30675
30678
  // ../bridge/src/agents/acp/clients/kill-process-tree.ts
30676
- var import_tree_kill = __toESM(require_tree_kill());
30679
+ var import_tree_kill = __toESM(require_tree_kill(), 1);
30677
30680
  import { promisify } from "node:util";
30678
30681
  var treeKillAsync = promisify(import_tree_kill.default);
30679
30682
  var ACP_PROCESS_TREE_KILL_GRACE_MS = 2500;
@@ -34962,7 +34965,7 @@ var coerce = {
34962
34965
  };
34963
34966
  var NEVER = INVALID;
34964
34967
 
34965
- // ../types/src/work-items.ts
34968
+ // ../core/src/work-items.ts
34966
34969
  var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
34967
34970
  var WorkItemProgressSchema = external_exports.object({
34968
34971
  remainingCriteria: external_exports.array(external_exports.string()).default([]),
@@ -35003,7 +35006,7 @@ var WorkItemSchema = external_exports.object({
35003
35006
  assignedToUserId: external_exports.string().optional()
35004
35007
  });
35005
35008
 
35006
- // ../types/src/user-profiles.ts
35009
+ // ../core/src/user-profiles.ts
35007
35010
  var UserWorkspaceProfileSchema = external_exports.object({
35008
35011
  id: external_exports.string(),
35009
35012
  workspaceId: external_exports.string(),
@@ -35014,7 +35017,7 @@ var UserWorkspaceProfileSchema = external_exports.object({
35014
35017
  learnings: external_exports.array(external_exports.string())
35015
35018
  });
35016
35019
 
35017
- // ../types/src/runtime.ts
35020
+ // ../core/src/runtime.ts
35018
35021
  var WorkspaceOwnerInfoSchema = external_exports.object({
35019
35022
  ownerId: external_exports.string(),
35020
35023
  ownerName: external_exports.string().optional(),
@@ -35029,7 +35032,7 @@ var WorkspaceRuntimeEntrySchema = external_exports.object({
35029
35032
  isOwner: external_exports.boolean().optional()
35030
35033
  });
35031
35034
 
35032
- // ../types/src/agent.ts
35035
+ // ../core/src/agent.ts
35033
35036
  var ProjectContextSchema = external_exports.object({
35034
35037
  projectId: external_exports.string(),
35035
35038
  context: external_exports.record(external_exports.unknown()).default({}),
@@ -35055,7 +35058,7 @@ var WebSocketMessageSchema = external_exports.object({
35055
35058
  error: external_exports.string().optional()
35056
35059
  });
35057
35060
 
35058
- // ../types/src/integrations/link-detection/linear.ts
35061
+ // ../core/src/integrations/link-detection/linear.ts
35059
35062
  function detectLinearLink(url2) {
35060
35063
  const linearMatch = url2.match(
35061
35064
  /https?:\/\/(?:app\.)?linear\.app\/([^/]+)\/issue\/([A-Z]+-\d+)/i
@@ -35072,7 +35075,7 @@ function detectLinearLink(url2) {
35072
35075
  return null;
35073
35076
  }
35074
35077
 
35075
- // ../types/src/integrations/link-detection/github.ts
35078
+ // ../core/src/integrations/link-detection/github.ts
35076
35079
  function detectGitHubLink(url2) {
35077
35080
  const githubIssueMatch = url2.match(
35078
35081
  /https?:\/\/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/i
@@ -35103,7 +35106,7 @@ function detectGitHubLink(url2) {
35103
35106
  return null;
35104
35107
  }
35105
35108
 
35106
- // ../types/src/integrations/link-detection/jira.ts
35109
+ // ../core/src/integrations/link-detection/jira.ts
35107
35110
  function detectJIRALink(url2) {
35108
35111
  const jiraMatch = url2.match(
35109
35112
  /https?:\/\/([^/]+)\.atlassian\.net\/(?:browse|jira\/software\/projects\/[^/]+\/issues)\/([A-Z]+-\d+)/i
@@ -35120,7 +35123,7 @@ function detectJIRALink(url2) {
35120
35123
  return null;
35121
35124
  }
35122
35125
 
35123
- // ../types/src/integrations/link-detection/notion.ts
35126
+ // ../core/src/integrations/link-detection/notion.ts
35124
35127
  function formatNotionPageId(hex3) {
35125
35128
  if (hex3.length !== 32) return hex3;
35126
35129
  return `${hex3.slice(0, 8)}-${hex3.slice(8, 12)}-${hex3.slice(12, 16)}-${hex3.slice(16, 20)}-${hex3.slice(20, 32)}`;
@@ -35152,48 +35155,7 @@ function detectNotionLink(url2) {
35152
35155
  return null;
35153
35156
  }
35154
35157
 
35155
- // ../types/src/integrations/link-detection/slack.ts
35156
- function detectSlackLink(url2) {
35157
- const archiveThreadMatch = url2.match(
35158
- /https?:\/\/(?:([^./]+)\.)?slack\.com\/archives\/([A-Z0-9]+)\/p(\d+)(?:\?.*)?$/i
35159
- );
35160
- if (archiveThreadMatch) {
35161
- return {
35162
- url: url2,
35163
- integrationType: "slack",
35164
- resourceType: "thread",
35165
- resourceId: `${archiveThreadMatch[2]}-${archiveThreadMatch[3]}`,
35166
- isChannel: false
35167
- };
35168
- }
35169
- const appThreadMatch = url2.match(
35170
- /https?:\/\/app\.slack\.com\/client\/([^/]+)\/([A-Z0-9]+)\/thread\/[A-Z0-9]+-(\d+)/i
35171
- );
35172
- if (appThreadMatch) {
35173
- return {
35174
- url: url2,
35175
- integrationType: "slack",
35176
- resourceType: "thread",
35177
- resourceId: `${appThreadMatch[2]}-${appThreadMatch[3]}`,
35178
- isChannel: false
35179
- };
35180
- }
35181
- const channelOnlyMatch = url2.match(
35182
- /https?:\/\/(?:app\.)?(?:([^./]+)\.)?slack\.com\/archives\/([A-Z0-9]+)\/?(\?.*)?$/i
35183
- );
35184
- if (channelOnlyMatch && !url2.includes("/p")) {
35185
- return {
35186
- url: url2,
35187
- integrationType: "slack",
35188
- resourceType: "channel",
35189
- resourceId: channelOnlyMatch[2],
35190
- isChannel: true
35191
- };
35192
- }
35193
- return null;
35194
- }
35195
-
35196
- // ../types/src/integrations/link-detection/zoom.ts
35158
+ // ../core/src/integrations/link-detection/zoom.ts
35197
35159
  function detectZoomLink(url2) {
35198
35160
  try {
35199
35161
  const u = new URL(url2);
@@ -35217,7 +35179,7 @@ function detectZoomLink(url2) {
35217
35179
  return null;
35218
35180
  }
35219
35181
 
35220
- // ../types/src/integrations/link-detection/asana.ts
35182
+ // ../core/src/integrations/link-detection/asana.ts
35221
35183
  var ASANA_TASK_GID = /\d{10,}/;
35222
35184
  function parseAsanaTaskGid(segment) {
35223
35185
  const trimmed2 = segment.trim();
@@ -35269,9 +35231,9 @@ function detectAsanaLink(url2) {
35269
35231
  return null;
35270
35232
  }
35271
35233
 
35272
- // ../types/src/integrations/link-detection/index.ts
35234
+ // ../core/src/integrations/link-detection/index.ts
35273
35235
  function detectIntegrationLink(url2) {
35274
- return detectLinearLink(url2) || detectGitHubLink(url2) || detectJIRALink(url2) || detectNotionLink(url2) || detectSlackLink(url2) || detectZoomLink(url2) || detectAsanaLink(url2);
35236
+ return detectLinearLink(url2) || detectGitHubLink(url2) || detectJIRALink(url2) || detectNotionLink(url2) || detectZoomLink(url2) || detectAsanaLink(url2);
35275
35237
  }
35276
35238
  function extractIntegrationLinks(text) {
35277
35239
  const urlRegex = /https?:\/\/[^\s<>"{}|\\^`[\]]+/gi;
@@ -35284,10 +35246,10 @@ function extractIntegrationLinks(text) {
35284
35246
  return links;
35285
35247
  }
35286
35248
  function extractFetchableIntegrationLinks(text) {
35287
- return extractIntegrationLinks(text).filter((link) => !(link.integrationType === "slack" && link.isChannel));
35249
+ return extractIntegrationLinks(text);
35288
35250
  }
35289
35251
 
35290
- // ../types/src/checkpoints.ts
35252
+ // ../core/src/checkpoints.ts
35291
35253
  var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
35292
35254
  var CheckpointSummarySchema = external_exports.object({
35293
35255
  id: external_exports.string(),
@@ -35299,11 +35261,11 @@ var CheckpointSummarySchema = external_exports.object({
35299
35261
  updatedAt: external_exports.string()
35300
35262
  });
35301
35263
 
35302
- // ../types/src/threads.ts
35264
+ // ../core/src/threads.ts
35303
35265
  var ThreadMetaSchema = external_exports.object({
35304
35266
  threadId: external_exports.string(),
35305
35267
  workspaceId: external_exports.string(),
35306
- /** External source (e.g. slack, discord); null if internal-only */
35268
+ /** External source (e.g. discord); null if internal-only */
35307
35269
  externalSource: external_exports.string().nullable(),
35308
35270
  /** Id in the external system (e.g. channel_id + thread_ts) */
35309
35271
  externalId: external_exports.string().nullable(),
@@ -35328,15 +35290,15 @@ var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
35328
35290
  threadId: external_exports.string()
35329
35291
  });
35330
35292
 
35331
- // ../types/src/content-items.ts
35332
- var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
35293
+ // ../core/src/content-items.ts
35294
+ var ContentSourceSchema = external_exports.enum(["notion", "doc", "other"]);
35333
35295
  var ContentItemMetaSchema = external_exports.object({
35334
35296
  contentId: external_exports.string(),
35335
35297
  workspaceId: external_exports.string(),
35336
35298
  source: ContentSourceSchema,
35337
35299
  /** Id in the external system (e.g. Notion page id, doc url) */
35338
35300
  externalId: external_exports.string(),
35339
- /** If source is slack_thread, points to Thread DO id */
35301
+ /** Optional linked thread DO id */
35340
35302
  threadId: external_exports.string().nullable(),
35341
35303
  title: external_exports.string().optional(),
35342
35304
  createdAt: external_exports.string(),
@@ -35351,7 +35313,7 @@ var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
35351
35313
  contentId: external_exports.string()
35352
35314
  });
35353
35315
 
35354
- // ../types/src/stories.ts
35316
+ // ../core/src/stories.ts
35355
35317
  var StoryMetaSchema = external_exports.object({
35356
35318
  storyId: external_exports.string(),
35357
35319
  workspaceId: external_exports.string(),
@@ -35375,7 +35337,7 @@ var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
35375
35337
  storyId: external_exports.string()
35376
35338
  });
35377
35339
 
35378
- // ../types/src/sessions.ts
35340
+ // ../core/src/sessions.ts
35379
35341
  var SessionMetaSchema = external_exports.object({
35380
35342
  sessionId: external_exports.string(),
35381
35343
  workspaceId: external_exports.string(),
@@ -35429,104 +35391,7 @@ function isUserEndedSessionTurnErrorText(errorText) {
35429
35391
  return LEGACY_USER_ENDED_SESSION_TURN_ERRORS.includes(raw);
35430
35392
  }
35431
35393
 
35432
- // ../types/src/session-kind.ts
35433
- var SESSION_KINDS = ["regular", "planned"];
35434
- var SESSION_KIND_SET = new Set(SESSION_KINDS);
35435
-
35436
- // ../types/src/diff/line-diff.ts
35437
- function normalizeDiffLineText(line) {
35438
- return line.replace(/\r$/, "").replace(/\s*\\s*$/, "");
35439
- }
35440
- function normalizePatchContent(patch) {
35441
- return patch.replace(/^\n+/, "").replace(/\n+$/, "");
35442
- }
35443
- function splitTextIntoDiffLines(text) {
35444
- if (text.length === 0) return [];
35445
- const lines = text.split("\n").map((line) => normalizeDiffLineText(line));
35446
- if (text.endsWith("\n") && lines.at(-1) === "") {
35447
- lines.pop();
35448
- }
35449
- return lines;
35450
- }
35451
- function createEofNewlineDiffLine(change) {
35452
- return {
35453
- type: change === "added" ? "add" : "remove",
35454
- line: "",
35455
- oldLineNo: null,
35456
- newLineNo: null,
35457
- eofNewlineChange: change
35458
- };
35459
- }
35460
- function hasSameLogicalLines(left, right) {
35461
- return left.length === right.length && left.every((line, index) => line === right[index]);
35462
- }
35463
- function detectEofNewlineChange(oldText, newText, oldLines, newLines) {
35464
- if (!hasSameLogicalLines(oldLines, newLines) || oldLines.length === 0) return null;
35465
- if (!oldText.endsWith("\n") && newText.endsWith("\n")) return "added";
35466
- if (oldText.endsWith("\n") && !newText.endsWith("\n")) return "removed";
35467
- return null;
35468
- }
35469
- function computeLineDiff(oldText, newText) {
35470
- const oldLines = splitTextIntoDiffLines(oldText);
35471
- const newLines = splitTextIntoDiffLines(newText);
35472
- const m = oldLines.length;
35473
- const n = newLines.length;
35474
- const dp = Array(m + 1);
35475
- for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
35476
- for (let i2 = 1; i2 <= m; i2++) {
35477
- for (let j2 = 1; j2 <= n; j2++) {
35478
- if (oldLines[i2 - 1] === newLines[j2 - 1]) {
35479
- dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
35480
- } else {
35481
- dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
35482
- }
35483
- }
35484
- }
35485
- const result = [];
35486
- let i = m;
35487
- let j = n;
35488
- while (i > 0 || j > 0) {
35489
- if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
35490
- result.unshift({ type: "context", line: oldLines[i - 1] });
35491
- i--;
35492
- j--;
35493
- } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
35494
- result.unshift({ type: "add", line: newLines[j - 1] });
35495
- j--;
35496
- } else {
35497
- result.unshift({ type: "remove", line: oldLines[i - 1] });
35498
- i--;
35499
- }
35500
- }
35501
- const eofNewlineChange = detectEofNewlineChange(oldText, newText, oldLines, newLines);
35502
- if (eofNewlineChange) result.push(createEofNewlineDiffLine(eofNewlineChange));
35503
- return result;
35504
- }
35505
- function editSnippetToUnifiedDiff(filePath, oldText, newText) {
35506
- const lines = computeLineDiff(oldText, newText);
35507
- const out = [`--- ${filePath}`, `+++ ${filePath}`];
35508
- for (const d of lines) {
35509
- if (d.eofNewlineChange) {
35510
- const previous = out.at(-1);
35511
- if (previous?.startsWith(" ")) {
35512
- const line = previous.slice(1);
35513
- out.pop();
35514
- if (d.eofNewlineChange === "added") {
35515
- out.push(`-${line}`, "\", `+${line}`);
35516
- } else {
35517
- out.push(`-${line}`, `+${line}`, "\");
35518
- }
35519
- continue;
35520
- }
35521
- }
35522
- if (d.type === "add") out.push(`+${d.line}`);
35523
- else if (d.type === "remove") out.push(`-${d.line}`);
35524
- else out.push(` ${d.line}`);
35525
- }
35526
- return out.join("\n");
35527
- }
35528
-
35529
- // ../types/src/artifacts.ts
35394
+ // ../core/src/artifacts.ts
35530
35395
  var ArtifactMetaSchema = external_exports.object({
35531
35396
  artifactId: external_exports.string(),
35532
35397
  workspaceId: external_exports.string(),
@@ -35541,7 +35406,7 @@ var ArtifactMetaSchema = external_exports.object({
35541
35406
  updatedAt: external_exports.string()
35542
35407
  });
35543
35408
 
35544
- // ../types/src/templates.ts
35409
+ // ../core/src/templates.ts
35545
35410
  var TemplateMetaSchema = external_exports.object({
35546
35411
  templateId: external_exports.string(),
35547
35412
  workspaceId: external_exports.string(),
@@ -35552,7 +35417,7 @@ var TemplateMetaSchema = external_exports.object({
35552
35417
  updatedAt: external_exports.string()
35553
35418
  });
35554
35419
 
35555
- // ../types/src/git-repos.ts
35420
+ // ../core/src/git-repos.ts
35556
35421
  var GitRepoMetaSchema = external_exports.object({
35557
35422
  /** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
35558
35423
  repoId: external_exports.string(),
@@ -35565,7 +35430,7 @@ var GitRepoMetaSchema = external_exports.object({
35565
35430
  updatedAt: external_exports.string()
35566
35431
  });
35567
35432
 
35568
- // ../types/src/mcp/bridge-mcp-constants.ts
35433
+ // ../core/src/mcp/bridge-mcp-constants.ts
35569
35434
  var GET_INTEGRATION_CONTENT_TOOL = "get_integration_content";
35570
35435
  var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
35571
35436
  var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
@@ -35575,12 +35440,12 @@ var BRIDGE_MCP_TOOL_LABELS = {
35575
35440
  [GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL]: "Read parent session transcript"
35576
35441
  };
35577
35442
 
35578
- // ../types/src/prompts/server.ts
35443
+ // ../core/src/prompts/server.ts
35579
35444
  function isRunnableBridgePromptTurnServerState(state) {
35580
35445
  return state === "queued" || state === "requeued" || state === "requeued_with_revert";
35581
35446
  }
35582
35447
 
35583
- // ../types/src/claude-code-permission-mode.ts
35448
+ // ../core/src/claude-code-permission-mode.ts
35584
35449
  var CLAUDE_CODE_PERMISSION_MODES = [
35585
35450
  "default",
35586
35451
  "acceptEdits",
@@ -35594,7 +35459,7 @@ function isClaudeCodePermissionMode(value) {
35594
35459
  return MODE_SET.has(value);
35595
35460
  }
35596
35461
 
35597
- // ../types/src/codex-permission-mode.ts
35462
+ // ../core/src/codex-permission-mode.ts
35598
35463
  function isCodexPermissionMode(value) {
35599
35464
  return value.trim() !== "";
35600
35465
  }
@@ -35604,7 +35469,7 @@ function normalizeCodexPermissionModeInput(raw) {
35604
35469
  return isCodexPermissionMode(t) ? t : null;
35605
35470
  }
35606
35471
 
35607
- // ../types/src/cli-permission-mode.ts
35472
+ // ../core/src/cli-permission-mode.ts
35608
35473
  var CLI_PERMISSION_MODE_DEFAULT = "default";
35609
35474
  var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
35610
35475
  function normalizeCliPermissionModeInput(raw) {
@@ -35615,7 +35480,7 @@ function normalizeCliPermissionModeInput(raw) {
35615
35480
  return CLI_PERMISSION_MODE_DEFAULT;
35616
35481
  }
35617
35482
 
35618
- // ../types/src/acp-permission-auto-approve.ts
35483
+ // ../core/src/acp-permission-auto-approve.ts
35619
35484
  function isRejectKind(kind) {
35620
35485
  return kind === "reject_once" || kind === "reject_always";
35621
35486
  }
@@ -35672,7 +35537,7 @@ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
35672
35537
  };
35673
35538
  }
35674
35539
 
35675
- // ../types/src/agent-config.ts
35540
+ // ../core/src/agent-config.ts
35676
35541
  var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
35677
35542
  var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
35678
35543
  var AGENT_CONFIG_CODEX_PERMISSION_MODE_KEY = "codex_permission_mode";
@@ -35700,11 +35565,104 @@ function getAgentModelFromAgentConfig(config2) {
35700
35565
  return t !== "" ? t : null;
35701
35566
  }
35702
35567
 
35703
- // ../types/src/overview/heatmap/constants.ts
35568
+ // ../core/src/diff/line-diff.ts
35569
+ function normalizeDiffLineText(line) {
35570
+ return line.replace(/\r$/, "").replace(/\s*\\s*$/, "");
35571
+ }
35572
+ function normalizePatchContent(patch) {
35573
+ return patch.replace(/^\n+/, "").replace(/\n+$/, "");
35574
+ }
35575
+ function splitTextIntoDiffLines(text) {
35576
+ if (text.length === 0) return [];
35577
+ const lines = text.split("\n").map((line) => normalizeDiffLineText(line));
35578
+ if (text.endsWith("\n") && lines.at(-1) === "") {
35579
+ lines.pop();
35580
+ }
35581
+ return lines;
35582
+ }
35583
+ function createEofNewlineDiffLine(change) {
35584
+ return {
35585
+ type: change === "added" ? "add" : "remove",
35586
+ line: "",
35587
+ oldLineNo: null,
35588
+ newLineNo: null,
35589
+ eofNewlineChange: change
35590
+ };
35591
+ }
35592
+ function hasSameLogicalLines(left, right) {
35593
+ return left.length === right.length && left.every((line, index) => line === right[index]);
35594
+ }
35595
+ function detectEofNewlineChange(oldText, newText, oldLines, newLines) {
35596
+ if (!hasSameLogicalLines(oldLines, newLines) || oldLines.length === 0) return null;
35597
+ if (!oldText.endsWith("\n") && newText.endsWith("\n")) return "added";
35598
+ if (oldText.endsWith("\n") && !newText.endsWith("\n")) return "removed";
35599
+ return null;
35600
+ }
35601
+ function computeLineDiff(oldText, newText) {
35602
+ const oldLines = splitTextIntoDiffLines(oldText);
35603
+ const newLines = splitTextIntoDiffLines(newText);
35604
+ const m = oldLines.length;
35605
+ const n = newLines.length;
35606
+ const dp = Array(m + 1);
35607
+ for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
35608
+ for (let i2 = 1; i2 <= m; i2++) {
35609
+ for (let j2 = 1; j2 <= n; j2++) {
35610
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
35611
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
35612
+ } else {
35613
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
35614
+ }
35615
+ }
35616
+ }
35617
+ const result = [];
35618
+ let i = m;
35619
+ let j = n;
35620
+ while (i > 0 || j > 0) {
35621
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
35622
+ result.unshift({ type: "context", line: oldLines[i - 1] });
35623
+ i--;
35624
+ j--;
35625
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
35626
+ result.unshift({ type: "add", line: newLines[j - 1] });
35627
+ j--;
35628
+ } else {
35629
+ result.unshift({ type: "remove", line: oldLines[i - 1] });
35630
+ i--;
35631
+ }
35632
+ }
35633
+ const eofNewlineChange = detectEofNewlineChange(oldText, newText, oldLines, newLines);
35634
+ if (eofNewlineChange) result.push(createEofNewlineDiffLine(eofNewlineChange));
35635
+ return result;
35636
+ }
35637
+ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
35638
+ const lines = computeLineDiff(oldText, newText);
35639
+ const out = [`--- ${filePath}`, `+++ ${filePath}`];
35640
+ for (const d of lines) {
35641
+ if (d.eofNewlineChange) {
35642
+ const previous = out.at(-1);
35643
+ if (previous?.startsWith(" ")) {
35644
+ const line = previous.slice(1);
35645
+ out.pop();
35646
+ if (d.eofNewlineChange === "added") {
35647
+ out.push(`-${line}`, "\", `+${line}`);
35648
+ } else {
35649
+ out.push(`-${line}`, `+${line}`, "\");
35650
+ }
35651
+ continue;
35652
+ }
35653
+ }
35654
+ if (d.type === "add") out.push(`+${d.line}`);
35655
+ else if (d.type === "remove") out.push(`-${d.line}`);
35656
+ else out.push(` ${d.line}`);
35657
+ }
35658
+ return out.join("\n");
35659
+ }
35660
+
35661
+ // ../core/src/overview/heatmap/constants.ts
35704
35662
  var HOUR_MS = 36e5;
35705
35663
  var DAY_MS = 24 * HOUR_MS;
35706
35664
 
35707
- // ../types/src/hosts/skus.ts
35665
+ // ../core/src/hosts/skus.ts
35708
35666
  function defineHostSku(params) {
35709
35667
  return structuredClone(params);
35710
35668
  }
@@ -35738,7 +35696,7 @@ var HOST_SKUS_BY_ID = {
35738
35696
  [FLY_DEFAULT_HOST_SKU.id]: FLY_DEFAULT_HOST_SKU
35739
35697
  };
35740
35698
 
35741
- // ../types/src/bridges/agents/types.ts
35699
+ // ../core/src/bridges/agents/types.ts
35742
35700
  var INSTALLABLE_BRIDGE_AGENTS = [
35743
35701
  { value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
35744
35702
  { value: "codex-acp", label: "Codex", tokenLabel: "OpenAI API key", tokenEnvVar: "OPENAI_API_KEY" },
@@ -35746,12 +35704,12 @@ var INSTALLABLE_BRIDGE_AGENTS = [
35746
35704
  { value: "opencode", label: "OpenCode agent", tokenLabel: "Provider API key", tokenEnvVar: "OPENCODE_API_KEY" }
35747
35705
  ];
35748
35706
 
35749
- // ../types/src/agent-subscriptions.ts
35707
+ // ../core/src/agent-subscriptions.ts
35750
35708
  var AGENT_SUBSCRIPTION_TYPES = INSTALLABLE_BRIDGE_AGENTS.map(
35751
35709
  (a) => a.value
35752
35710
  );
35753
35711
 
35754
- // ../types/src/role-payment-model.ts
35712
+ // ../core/src/role-payment-model.ts
35755
35713
  var ROLE_FIXED_AMOUNT_USD_MAX = 5e4;
35756
35714
  var ROLE_PER_SESSION_USD_MIN = 0;
35757
35715
  var ROLE_PER_SESSION_USD_MAX = 200;
@@ -35776,14 +35734,14 @@ var RolePaymentModelWireSchema = external_exports.discriminatedUnion("type", [
35776
35734
  })
35777
35735
  ]);
35778
35736
 
35779
- // ../types/src/role-period-days.ts
35737
+ // ../core/src/role-period-days.ts
35780
35738
  var ROLE_PERIOD_MIN_DAYS = 1;
35781
35739
  var ROLE_PERIOD_DAYS_PER_WEEK = 5;
35782
35740
  var ROLE_PERIOD_WEEKS_PER_MONTH = 4;
35783
35741
  var ROLE_PERIOD_DAYS_PER_MONTH = ROLE_PERIOD_DAYS_PER_WEEK * ROLE_PERIOD_WEEKS_PER_MONTH;
35784
35742
  var ROLE_PERIOD_MAX_DAYS = ROLE_PERIOD_DAYS_PER_MONTH * 6;
35785
35743
 
35786
- // ../types/src/role-length.ts
35744
+ // ../core/src/role-length.ts
35787
35745
  var ROLE_LENGTH_MAX_SESSIONS_MIN = 1;
35788
35746
  var ROLE_LENGTH_MAX_SESSIONS_MAX = 50;
35789
35747
  var ROLE_LENGTH_SESSIONS_UNLIMITED_STOP = ROLE_LENGTH_MAX_SESSIONS_MAX + 8;
@@ -35798,7 +35756,7 @@ var RoleLengthWireSchema = external_exports.discriminatedUnion("type", [
35798
35756
  external_exports.object({ type: external_exports.literal("session_count"), max_sessions: MaxSessionsSchema })
35799
35757
  ]);
35800
35758
 
35801
- // ../types/src/role-access-restrictions.ts
35759
+ // ../core/src/role-access-restrictions.ts
35802
35760
  var EMPTY_ROLE_ACCESS_RESTRICTIONS = {
35803
35761
  sessionsOwnAndExplicitOnly: false,
35804
35762
  bridgesOwnAndExplicitOnly: false,
@@ -35816,7 +35774,7 @@ function roleAccessRestrictionsToWire(restrictions) {
35816
35774
  };
35817
35775
  }
35818
35776
 
35819
- // ../types/src/role-details.ts
35777
+ // ../core/src/role-details.ts
35820
35778
  var InitialPeriodDaysSchema = external_exports.number().int().min(ROLE_PERIOD_MIN_DAYS).max(ROLE_PERIOD_MAX_DAYS);
35821
35779
  var AgentSubscriptionIdsSchema = external_exports.array(external_exports.string().min(1)).default([]);
35822
35780
  var BoolFalseSchema = external_exports.boolean().default(false);
@@ -39754,7 +39712,31 @@ function createBridgeOnRequest(opts) {
39754
39712
  }
39755
39713
 
39756
39714
  // ../bridge/src/agents/acp/hooks/bridge-on-session-update/constants.ts
39757
- var PATH_SNAPSHOT_DEBOUNCE_MS = 500;
39715
+ var PATH_SNAPSHOT_DEBOUNCE_MS = 150;
39716
+
39717
+ // ../bridge/src/agents/acp/hooks/bridge-on-session-update/pair-path-snapshot-changes.ts
39718
+ function isDeleted(c) {
39719
+ return c.newText === "" && c.oldText.length > 0;
39720
+ }
39721
+ function isAdded(c) {
39722
+ return c.oldText === "" && c.newText.length > 0 && !c.movedFromPath;
39723
+ }
39724
+ function pairPathSnapshotChanges(changes) {
39725
+ const out = changes.map((c) => ({ ...c }));
39726
+ const deleted = out.filter(isDeleted);
39727
+ const usedDeleted = /* @__PURE__ */ new Set();
39728
+ for (const add of out) {
39729
+ if (!isAdded(add)) continue;
39730
+ const match = deleted.find(
39731
+ (d) => !usedDeleted.has(d.displayPath) && d.oldText === add.newText && d.displayPath !== add.displayPath
39732
+ );
39733
+ if (!match) continue;
39734
+ add.movedFromPath = match.displayPath;
39735
+ add.oldText = match.oldText;
39736
+ usedDeleted.add(match.displayPath);
39737
+ }
39738
+ return out.filter((c) => !(isDeleted(c) && usedDeleted.has(c.displayPath))).map(({ displayPath: _d, ...payload }) => payload);
39739
+ }
39758
39740
 
39759
39741
  // ../bridge/src/agents/acp/hooks/bridge-on-session-update/tool-key.ts
39760
39742
  function getToolCallId(params) {
@@ -39846,26 +39828,31 @@ var PathSnapshotTracker = class {
39846
39828
  if (!beforeMap || beforeMap.size === 0) return;
39847
39829
  this.beforeByToolKey.delete(toolKey);
39848
39830
  if (!send || !runId || !sessionId) return;
39831
+ const pending2 = [];
39849
39832
  for (const [displayPath, oldText] of beforeMap) {
39850
39833
  const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
39851
39834
  if (oldText === newText) continue;
39852
39835
  const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
39853
39836
  const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
39837
+ pending2.push({
39838
+ type: "session_file_change",
39839
+ sessionId,
39840
+ runId,
39841
+ path: displayPath,
39842
+ displayPath,
39843
+ oldText,
39844
+ newText,
39845
+ patchContent,
39846
+ isDirectory: dirFlags.isDirectory,
39847
+ directoryRemoved: dirFlags.directoryRemoved
39848
+ });
39849
+ }
39850
+ for (const payload of pairPathSnapshotChanges(pending2)) {
39854
39851
  try {
39855
- send({
39856
- type: "session_file_change",
39857
- sessionId,
39858
- runId,
39859
- path: displayPath,
39860
- oldText,
39861
- newText,
39862
- patchContent,
39863
- isDirectory: dirFlags.isDirectory,
39864
- directoryRemoved: dirFlags.directoryRemoved
39865
- });
39866
- sentPaths.add(displayPath);
39852
+ send(payload);
39853
+ sentPaths.add(payload.path);
39867
39854
  } catch (err) {
39868
- log2(`[Bridge service] Session file change failed for ${displayPath}: ${errorMessage(err)}`);
39855
+ log2(`[Bridge service] Session file change failed for ${payload.path}: ${errorMessage(err)}`);
39869
39856
  }
39870
39857
  }
39871
39858
  }
@@ -40970,16 +40957,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
40970
40957
  // ../bridge/src/agents/acp/prompts/report-post-turn-enrichment.ts
40971
40958
  function reportPostTurnEnrichment(options) {
40972
40959
  void (async () => {
40973
- const {
40974
- sessionId,
40975
- runId,
40976
- agentCwd,
40977
- result,
40978
- sendSessionUpdate,
40979
- log: log2
40980
- } = options;
40960
+ const { sessionId, runId, agentCwd, sendSessionUpdate, log: log2 } = options;
40981
40961
  await yieldToEventLoop();
40982
- if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
40962
+ if (sessionId && runId && sendSessionUpdate && agentCwd) {
40983
40963
  await collectTurnGitDiffFromPreTurnSnapshot({
40984
40964
  sessionId,
40985
40965
  runId,
@@ -43591,7 +43571,7 @@ function createBridgeHeartbeatController(params) {
43591
43571
  }
43592
43572
 
43593
43573
  // ../bridge/src/cli/cli-version.ts
43594
- var CLI_VERSION2 = "0.1.95".length > 0 ? "0.1.95" : "0.0.0-dev";
43574
+ var CLI_VERSION2 = "0.1.97".length > 0 ? "0.1.97" : "0.0.0-dev";
43595
43575
 
43596
43576
  // ../bridge/src/connection/identify/send-bridge-identify.ts
43597
43577
  function sendBridgeIdentify(ws, params) {
@@ -54085,6 +54065,7 @@ async function executePromptQueueActions(actions, deps) {
54085
54065
  continue;
54086
54066
  }
54087
54067
  if (action.type === "start_run") {
54068
+ if (getRunIdQueueKey(action.turn.turnId)) continue;
54088
54069
  const ok = await markTurnRunning(action.queueKey, action.turn, deps);
54089
54070
  if (!ok) {
54090
54071
  report[action.queueKey] = [{ turnId: action.turn.turnId, cliState: "failed" }];
@@ -54135,7 +54116,7 @@ var SLOW_QUEUE_SYNC_MS = 2e3;
54135
54116
  async function persistAndReconcileQueue(queueKey, serverTurns, deps) {
54136
54117
  const prev = await readPersistedQueue(queueKey);
54137
54118
  const merged = mergeServerSnapshotWithLocal(queueKey, serverTurns, prev);
54138
- const liveCheck = (runId) => deps.acpManager.isRegisteredRun(runId);
54119
+ const liveCheck = (runId) => deps.acpManager.isRegisteredRun(runId) || getRunIdQueueKey(runId) != null;
54139
54120
  const actions = reconcileQueueActions(queueKey, merged.turns, liveCheck);
54140
54121
  merged.turns = applyStaleRunningNormalization(merged.turns, liveCheck);
54141
54122
  await writePersistedQueue(merged);
@@ -57052,7 +57033,7 @@ var SESSION_ID_SCHEMA2 = {
57052
57033
  var INTEGRATION_CONTENT_MCP_TOOL_DEFINITIONS = [
57053
57034
  {
57054
57035
  name: GET_INTEGRATION_CONTENT_TOOL2,
57055
- description: "Fetch the full content of a supported external integration link (Linear, GitHub, Jira, Notion, Slack thread, Zoom meeting, Asana). Requires sessionId and url. By default, links the URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false to fetch content only (e.g. additional context links). Returns an error when the URL is unsupported, the integration is not connected, or content is temporarily unavailable (retry may succeed).",
57036
+ description: "Fetch the full content of a supported external integration link (Linear, GitHub, Jira, Notion, Zoom meeting, Asana). Requires sessionId and url. By default, links the URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false to fetch content only (e.g. additional context links). Returns an error when the URL is unsupported, the integration is not connected, or content is temporarily unavailable (retry may succeed).",
57056
57037
  inputSchema: {
57057
57038
  type: "object",
57058
57039
  properties: {
@@ -57260,7 +57241,7 @@ async function enrichForkedSessionPromptForAgent(params) {
57260
57241
  function buildIntegrationContentAgentPromptNote(sessionId) {
57261
57242
  const sessionRef = sessionId.trim();
57262
57243
  return [
57263
- "The user message includes link(s) to external integration resources (Linear, GitHub, Jira, Notion, Slack thread, Zoom, or Asana).",
57244
+ "The user message includes link(s) to external integration resources (Linear, GitHub, Jira, Notion, Zoom, or Asana).",
57264
57245
  "Use the get_integration_content MCP tool on the buildautomaton-bridge server to fetch the full content of each link.",
57265
57246
  `When calling the tool, pass sessionId "${sessionRef}" and the URL as url.`,
57266
57247
  "By default the tool links the fetched URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false when fetching additional links for context only (after the primary ticket is linked, or when you do not want association).",