session-collab-mcp 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -188,12 +188,20 @@ Coordinate sessions and persist context across conversations.
188
188
 
189
189
  1. **On start**: \`collab_session_start\` with project_root
190
190
  2. **Before editing**: \`collab_claim\` action="check"
191
- 3. **For changes**: \`collab_claim\` action="create" (blocked by default if another active session conflicts)
191
+ 3. **For changes**: \`collab_claim\` action="create" (smart mode claims safe files and queues blocked files)
192
192
  4. **Save context**: \`collab_memory_save\` for important findings
193
193
  5. **While working**: \`collab_session_update\` with current_task/todos
194
194
  6. **When done**: \`collab_claim\` action="release"
195
195
  7. **On end**: \`collab_session_end\`
196
196
 
197
+ ## Conflict Handling
198
+
199
+ - \`strict\`: conflicting claims are blocked; coordinate before editing.
200
+ - \`smart\` (default): same-file work can proceed when symbol claims do not overlap; mixed requests claim safe files and create coordination requests for blocked files.
201
+ - \`bypass\`: overlapping claims require explicit \`allow_conflicts=true\` and return a warning.
202
+ - If a file is blocked, narrow the claim to specific symbols before retrying. Do not overwrite, revert, or delete another active session's work.
203
+ - Check \`collab_status\` or \`collab_session_list\` for pending coordination requests.
204
+
197
205
  ## Memory Categories
198
206
 
199
207
  - **finding**: Discovered facts, root causes
@@ -4286,6 +4294,29 @@ function createToolResult(text, isError = false) {
4286
4294
  };
4287
4295
  }
4288
4296
 
4297
+ // src/db/types.ts
4298
+ function getPriorityLevel(priority) {
4299
+ if (priority >= 90) return { value: priority, level: "critical", label: "Critical (90-100)" };
4300
+ if (priority >= 70) return { value: priority, level: "high", label: "High (70-89)" };
4301
+ if (priority >= 40) return { value: priority, level: "normal", label: "Normal (40-69)" };
4302
+ return { value: priority, level: "low", label: "Low (0-39)" };
4303
+ }
4304
+ var DEFAULT_SESSION_CONFIG = {
4305
+ mode: "smart",
4306
+ allow_release_others: false,
4307
+ auto_release_stale: false,
4308
+ stale_threshold_hours: 2,
4309
+ auto_release_immediate: false,
4310
+ auto_release_delay_minutes: 5
4311
+ };
4312
+ var SCOPE_WAIT_MINUTES = {
4313
+ small: 30,
4314
+ medium: 120,
4315
+ // 2 hours
4316
+ large: 480
4317
+ // 8 hours
4318
+ };
4319
+
4289
4320
  // src/utils/crypto.ts
4290
4321
  function generateId() {
4291
4322
  return crypto.randomUUID();
@@ -4681,6 +4712,144 @@ async function removeSessionFromAllQueues(db, sessionId) {
4681
4712
  const result = await db.prepare("DELETE FROM claim_queue WHERE session_id = ?").bind(sessionId).run();
4682
4713
  return result.meta.changes;
4683
4714
  }
4715
+ async function getNextQueuePosition(db, claimId) {
4716
+ const result = await db.prepare("SELECT MAX(position) as max_pos FROM claim_queue WHERE claim_id = ?").bind(claimId).first();
4717
+ return (result?.max_pos ?? 0) + 1;
4718
+ }
4719
+ async function calculateEstimatedWait(db, claimId, position) {
4720
+ const result = await db.prepare(
4721
+ `SELECT scope FROM claim_queue
4722
+ WHERE claim_id = ? AND position < ?
4723
+ ORDER BY priority DESC, position ASC`
4724
+ ).bind(claimId, position).all();
4725
+ let totalMinutes = 0;
4726
+ for (const entry of result.results) {
4727
+ totalMinutes += SCOPE_WAIT_MINUTES[entry.scope] ?? SCOPE_WAIT_MINUTES.medium;
4728
+ }
4729
+ const claim = await getClaim(db, claimId);
4730
+ if (claim) {
4731
+ totalMinutes += Math.round(SCOPE_WAIT_MINUTES[claim.scope] / 2);
4732
+ }
4733
+ return totalMinutes;
4734
+ }
4735
+ async function joinQueue(db, params) {
4736
+ const existing = await db.prepare("SELECT * FROM claim_queue WHERE claim_id = ? AND session_id = ?").bind(params.claim_id, params.session_id).first();
4737
+ if (existing) {
4738
+ return existing;
4739
+ }
4740
+ const id = generateId();
4741
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4742
+ const priority = params.priority ?? 50;
4743
+ const scope = params.scope ?? "medium";
4744
+ const position = await getNextQueuePosition(db, params.claim_id);
4745
+ const estimatedWait = await calculateEstimatedWait(db, params.claim_id, position);
4746
+ await db.prepare(
4747
+ `INSERT INTO claim_queue (id, claim_id, session_id, intent, position, priority, scope, estimated_wait_minutes, created_at)
4748
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
4749
+ ).bind(id, params.claim_id, params.session_id, params.intent, position, priority, scope, estimatedWait, now).run();
4750
+ return {
4751
+ id,
4752
+ claim_id: params.claim_id,
4753
+ session_id: params.session_id,
4754
+ intent: params.intent,
4755
+ position,
4756
+ priority,
4757
+ scope,
4758
+ estimated_wait_minutes: estimatedWait,
4759
+ created_at: now
4760
+ };
4761
+ }
4762
+ async function listQueue(db, params = {}) {
4763
+ let query = `
4764
+ SELECT
4765
+ q.*,
4766
+ s.name as session_name,
4767
+ c.session_id as owner_session_id,
4768
+ c.intent as claim_intent,
4769
+ cs.name as claim_session_name,
4770
+ GROUP_CONCAT(cf.file_path, '|||') as claim_files_concat
4771
+ FROM claim_queue q
4772
+ JOIN sessions s ON q.session_id = s.id
4773
+ JOIN claims c ON q.claim_id = c.id
4774
+ JOIN sessions cs ON c.session_id = cs.id
4775
+ LEFT JOIN claim_files cf ON c.id = cf.claim_id
4776
+ WHERE c.status = 'active'
4777
+ AND s.status = 'active'
4778
+ AND cs.status = 'active'
4779
+ `;
4780
+ const bindings = [];
4781
+ if (params.claim_id) {
4782
+ query += " AND q.claim_id = ?";
4783
+ bindings.push(params.claim_id);
4784
+ }
4785
+ if (params.session_id) {
4786
+ query += " AND q.session_id = ?";
4787
+ bindings.push(params.session_id);
4788
+ }
4789
+ if (params.owner_session_id) {
4790
+ query += " AND c.session_id = ?";
4791
+ bindings.push(params.owner_session_id);
4792
+ }
4793
+ query += " GROUP BY q.id ORDER BY q.priority DESC, q.position ASC";
4794
+ const result = await db.prepare(query).bind(...bindings).all();
4795
+ return result.results.map((entry) => ({
4796
+ ...entry,
4797
+ claim_files: entry.claim_files_concat ? entry.claim_files_concat.split("|||") : []
4798
+ }));
4799
+ }
4800
+ async function createNotification(db, params) {
4801
+ const id = generateId();
4802
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4803
+ const metadataJson = params.metadata ? JSON.stringify(params.metadata) : null;
4804
+ await db.prepare(
4805
+ `INSERT INTO notifications (id, session_id, type, title, message, reference_type, reference_id, metadata, created_at)
4806
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
4807
+ ).bind(
4808
+ id,
4809
+ params.session_id,
4810
+ params.type,
4811
+ params.title,
4812
+ params.message,
4813
+ params.reference_type ?? null,
4814
+ params.reference_id ?? null,
4815
+ metadataJson,
4816
+ now
4817
+ ).run();
4818
+ return {
4819
+ id,
4820
+ session_id: params.session_id,
4821
+ type: params.type,
4822
+ title: params.title,
4823
+ message: params.message,
4824
+ reference_type: params.reference_type ?? null,
4825
+ reference_id: params.reference_id ?? null,
4826
+ metadata: metadataJson,
4827
+ read_at: null,
4828
+ created_at: now
4829
+ };
4830
+ }
4831
+ async function notifyQueueOnClaimRelease(db, claimId, releasedBy, files) {
4832
+ const queuedSessions = await listQueue(db, { claim_id: claimId });
4833
+ let notified = 0;
4834
+ for (const entry of queuedSessions) {
4835
+ await createNotification(db, {
4836
+ session_id: entry.session_id,
4837
+ type: "queue_ready",
4838
+ title: "Claim released",
4839
+ message: `The claim for ${files.join(", ")} has been released. You can claim these files now.`,
4840
+ reference_type: "claim",
4841
+ reference_id: claimId,
4842
+ metadata: {
4843
+ claim_id: claimId,
4844
+ files,
4845
+ released_by: releasedBy,
4846
+ queue_position: entry.position
4847
+ }
4848
+ });
4849
+ notified++;
4850
+ }
4851
+ return notified;
4852
+ }
4684
4853
  async function logAuditEvent(db, params) {
4685
4854
  const id = generateId();
4686
4855
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -4953,22 +5122,6 @@ async function getProtectedFiles(db, sessionId) {
4953
5122
  });
4954
5123
  }
4955
5124
 
4956
- // src/db/types.ts
4957
- function getPriorityLevel(priority) {
4958
- if (priority >= 90) return { value: priority, level: "critical", label: "Critical (90-100)" };
4959
- if (priority >= 70) return { value: priority, level: "high", label: "High (70-89)" };
4960
- if (priority >= 40) return { value: priority, level: "normal", label: "Normal (40-69)" };
4961
- return { value: priority, level: "low", label: "Low (0-39)" };
4962
- }
4963
- var DEFAULT_SESSION_CONFIG = {
4964
- mode: "smart",
4965
- allow_release_others: false,
4966
- auto_release_stale: false,
4967
- stale_threshold_hours: 2,
4968
- auto_release_immediate: false,
4969
- auto_release_delay_minutes: 5
4970
- };
4971
-
4972
5125
  // src/mcp/schemas.ts
4973
5126
  var sessionIdSchema = external_exports.string().min(1, "session_id is required");
4974
5127
  var claimIdSchema = external_exports.string().min(1, "claim_id is required");
@@ -5148,6 +5301,35 @@ function parseJsonField(value) {
5148
5301
  return null;
5149
5302
  }
5150
5303
  }
5304
+ function formatIncomingCoordination(entry) {
5305
+ return {
5306
+ queue_id: entry.id,
5307
+ owner_claim_id: entry.claim_id,
5308
+ requested_by_session_id: entry.session_id,
5309
+ requested_by_session_name: entry.session_name,
5310
+ intent: entry.intent,
5311
+ files: entry.claim_files,
5312
+ priority: getPriorityLevel(entry.priority),
5313
+ position: entry.position,
5314
+ estimated_wait_minutes: entry.estimated_wait_minutes,
5315
+ created_at: entry.created_at
5316
+ };
5317
+ }
5318
+ function formatOutgoingCoordination(entry) {
5319
+ return {
5320
+ queue_id: entry.id,
5321
+ owner_claim_id: entry.claim_id,
5322
+ owner_session_id: entry.owner_session_id,
5323
+ owner_session_name: entry.claim_session_name,
5324
+ owner_intent: entry.claim_intent,
5325
+ intent: entry.intent,
5326
+ files: entry.claim_files,
5327
+ priority: getPriorityLevel(entry.priority),
5328
+ position: entry.position,
5329
+ estimated_wait_minutes: entry.estimated_wait_minutes,
5330
+ created_at: entry.created_at
5331
+ };
5332
+ }
5151
5333
  var sessionTools = [
5152
5334
  {
5153
5335
  name: "collab_session_start",
@@ -5381,6 +5563,8 @@ Decisions:
5381
5563
  const sessionsWithClaims = await Promise.all(
5382
5564
  sessions.map(async (session) => {
5383
5565
  const claims = await listClaims(db, { session_id: session.id, status: "active" });
5566
+ const incomingCoordination = await listQueue(db, { owner_session_id: session.id });
5567
+ const outgoingCoordination = await listQueue(db, { session_id: session.id });
5384
5568
  return {
5385
5569
  id: session.id,
5386
5570
  name: session.name,
@@ -5396,6 +5580,11 @@ Decisions:
5396
5580
  priority: getPriorityLevel(c.priority),
5397
5581
  created_at: c.created_at
5398
5582
  })),
5583
+ pending_coordination: {
5584
+ incoming: incomingCoordination.length,
5585
+ outgoing: outgoingCoordination.length
5586
+ },
5587
+ coordination_requests: incomingCoordination.map(formatIncomingCoordination),
5399
5588
  last_heartbeat: session.last_heartbeat
5400
5589
  };
5401
5590
  })
@@ -5479,6 +5668,8 @@ Decisions:
5479
5668
  const claims = await listClaims(db, { session_id: sessionId, status: "active" });
5480
5669
  const memories = await getActiveMemories(db, sessionId, { priority_threshold: 70, max_items: 10 });
5481
5670
  const allSessions = await listSessions(db, { project_root: session.project_root });
5671
+ const incomingCoordination = await listQueue(db, { owner_session_id: sessionId });
5672
+ const outgoingCoordination = await listQueue(db, { session_id: sessionId });
5482
5673
  return successResponse({
5483
5674
  session: {
5484
5675
  id: session.id,
@@ -5492,6 +5683,14 @@ Decisions:
5492
5683
  })),
5493
5684
  active_memories: memories.length,
5494
5685
  other_sessions: allSessions.filter((s) => s.id !== sessionId).length,
5686
+ pending_coordination: {
5687
+ incoming: incomingCoordination.length,
5688
+ outgoing: outgoingCoordination.length
5689
+ },
5690
+ coordination_requests: {
5691
+ incoming: incomingCoordination.map(formatIncomingCoordination),
5692
+ outgoing: outgoingCoordination.map(formatOutgoingCoordination)
5693
+ },
5495
5694
  message: `Session active. ${claims.length} claim(s), ${memories.length} memories.`
5496
5695
  });
5497
5696
  }
@@ -5501,11 +5700,155 @@ Decisions:
5501
5700
  }
5502
5701
 
5503
5702
  // src/mcp/tools/claim.ts
5703
+ function parseSessionConfig(session) {
5704
+ if (!session.config) {
5705
+ return DEFAULT_SESSION_CONFIG;
5706
+ }
5707
+ try {
5708
+ return { ...DEFAULT_SESSION_CONFIG, ...JSON.parse(session.config) };
5709
+ } catch {
5710
+ return DEFAULT_SESSION_CONFIG;
5711
+ }
5712
+ }
5713
+ function mapConflict(conflict, ownerSession) {
5714
+ return {
5715
+ claim_id: conflict.claim_id,
5716
+ session_id: conflict.session_id,
5717
+ session_name: conflict.session_name,
5718
+ file: conflict.file_path,
5719
+ intent: conflict.intent,
5720
+ scope: conflict.scope,
5721
+ created_at: conflict.created_at,
5722
+ conflict_level: conflict.conflict_level,
5723
+ symbol_name: conflict.symbol_name ?? null,
5724
+ symbol_type: conflict.symbol_type ?? null,
5725
+ current_task: ownerSession?.current_task ?? null,
5726
+ last_heartbeat: ownerSession?.last_heartbeat ?? null
5727
+ };
5728
+ }
5729
+ async function formatConflicts(db, conflicts) {
5730
+ const sessions = /* @__PURE__ */ new Map();
5731
+ for (const conflict of conflicts) {
5732
+ if (!sessions.has(conflict.session_id)) {
5733
+ sessions.set(conflict.session_id, await getSession(db, conflict.session_id));
5734
+ }
5735
+ }
5736
+ return conflicts.map((conflict) => mapConflict(conflict, sessions.get(conflict.session_id) ?? null));
5737
+ }
5738
+ function uniqueBlockedFiles(conflicts) {
5739
+ return Array.from(new Set(conflicts.map((conflict) => conflict.file_path)));
5740
+ }
5741
+ function filterSafeSymbols(symbols, safeFiles) {
5742
+ if (!symbols || symbols.length === 0) {
5743
+ return void 0;
5744
+ }
5745
+ const safeFileSet = new Set(safeFiles);
5746
+ const safeSymbols = symbols.filter((symbol) => safeFileSet.has(symbol.file));
5747
+ return safeSymbols.length > 0 ? safeSymbols : void 0;
5748
+ }
5749
+ function getCoordinationRecommendation(symbols, conflicts) {
5750
+ const hasFileLevelConflict = conflicts.some((conflict) => conflict.conflict_level === "file");
5751
+ if (symbols && symbols.length > 0 && hasFileLevelConflict) {
5752
+ return "provide_symbols_or_wait";
5753
+ }
5754
+ return "wait_for_release_or_coordinate";
5755
+ }
5756
+ async function createTrackedClaim(db, input) {
5757
+ const { claim } = await createClaim(db, {
5758
+ session_id: input.session_id,
5759
+ files: input.files,
5760
+ symbols: input.symbols,
5761
+ intent: input.intent,
5762
+ scope: input.scope,
5763
+ priority: input.priority
5764
+ });
5765
+ await logAuditEvent(db, {
5766
+ session_id: input.session_id,
5767
+ action: "claim_created",
5768
+ entity_type: "claim",
5769
+ entity_id: claim.id,
5770
+ metadata: { files: input.files, intent: input.intent }
5771
+ });
5772
+ await saveMemory(db, input.session_id, {
5773
+ category: "state",
5774
+ key: `claim_${claim.id}`,
5775
+ content: `Working on: ${input.intent}
5776
+ Files: ${input.files.join(", ")}`,
5777
+ priority: 60,
5778
+ related_claim_id: claim.id,
5779
+ metadata: { claim_id: claim.id, files: input.files }
5780
+ });
5781
+ return claim.id;
5782
+ }
5783
+ async function createCoordinationRequests(db, input, conflicts) {
5784
+ const grouped = /* @__PURE__ */ new Map();
5785
+ for (const conflict of conflicts) {
5786
+ const existing = grouped.get(conflict.claim_id);
5787
+ if (existing) {
5788
+ existing.files.add(conflict.file_path);
5789
+ } else {
5790
+ grouped.set(conflict.claim_id, {
5791
+ conflict,
5792
+ files: /* @__PURE__ */ new Set([conflict.file_path])
5793
+ });
5794
+ }
5795
+ }
5796
+ const requests = [];
5797
+ for (const { conflict, files } of grouped.values()) {
5798
+ const fileList = Array.from(files);
5799
+ const queueEntry = await joinQueue(db, {
5800
+ claim_id: conflict.claim_id,
5801
+ session_id: input.session_id,
5802
+ intent: input.intent,
5803
+ priority: input.priority,
5804
+ scope: input.scope
5805
+ });
5806
+ await logAuditEvent(db, {
5807
+ session_id: input.session_id,
5808
+ action: "queue_joined",
5809
+ entity_type: "queue",
5810
+ entity_id: queueEntry.id,
5811
+ metadata: {
5812
+ claim_id: conflict.claim_id,
5813
+ files: fileList,
5814
+ conflicting_session_id: conflict.session_id,
5815
+ conflicting_session_name: conflict.session_name ?? void 0,
5816
+ priority: queueEntry.priority,
5817
+ scope: queueEntry.scope
5818
+ }
5819
+ });
5820
+ await createNotification(db, {
5821
+ session_id: conflict.session_id,
5822
+ type: "conflict_detected",
5823
+ title: "Coordination requested",
5824
+ message: `Another session is waiting to coordinate work on ${fileList.join(", ")}.`,
5825
+ reference_type: "claim",
5826
+ reference_id: conflict.claim_id,
5827
+ metadata: {
5828
+ claim_id: conflict.claim_id,
5829
+ files: fileList,
5830
+ conflicting_session_id: input.session_id
5831
+ }
5832
+ });
5833
+ requests.push({
5834
+ queue_id: queueEntry.id,
5835
+ owner_claim_id: conflict.claim_id,
5836
+ owner_session_id: conflict.session_id,
5837
+ owner_session_name: conflict.session_name,
5838
+ requested_by_session_id: input.session_id,
5839
+ requested_intent: input.intent,
5840
+ files: fileList,
5841
+ position: queueEntry.position,
5842
+ estimated_wait_minutes: queueEntry.estimated_wait_minutes
5843
+ });
5844
+ }
5845
+ return requests;
5846
+ }
5504
5847
  var claimTools = [
5505
5848
  {
5506
5849
  name: "collab_claim",
5507
5850
  description: `Unified tool for file/symbol claims. Use action parameter to:
5508
- - "create": Declare files you're about to modify
5851
+ - "create": Declare files you're about to modify; smart mode queues blocked files for coordination
5509
5852
  - "check": Check if files are being worked on (ALWAYS call before editing)
5510
5853
  - "release": Release a claim when done
5511
5854
  - "list": List all active claims`,
@@ -5609,67 +5952,111 @@ async function handleClaimTool(db, name, args) {
5609
5952
  if (!sessionResult.valid) {
5610
5953
  return sessionResult.error;
5611
5954
  }
5955
+ const config = parseSessionConfig(sessionResult.session);
5612
5956
  const symbolFiles = (input.symbols ?? []).map((symbol) => symbol.file);
5613
5957
  const files = Array.from(/* @__PURE__ */ new Set([...input.files ?? [], ...symbolFiles]));
5614
5958
  const conflicts = await checkConflicts(db, files, input.session_id, input.symbols);
5615
- if (conflicts.length > 0 && !input.allow_conflicts) {
5959
+ const formattedConflicts = await formatConflicts(db, conflicts);
5960
+ const blockedFiles = uniqueBlockedFiles(conflicts);
5961
+ const safeFiles = files.filter((file) => !blockedFiles.includes(file));
5962
+ const safeSymbols = filterSafeSymbols(input.symbols, safeFiles);
5963
+ if (conflicts.length > 0 && config.mode === "strict") {
5616
5964
  return successResponse({
5617
5965
  success: false,
5618
5966
  status: "blocked_by_conflicts",
5619
5967
  files,
5620
5968
  symbols: input.symbols ?? [],
5621
- conflicts: conflicts.map((c) => ({
5622
- session_name: c.session_name,
5623
- file: c.file_path,
5624
- intent: c.intent
5625
- })),
5969
+ claimed_files: [],
5970
+ safe_files: safeFiles,
5971
+ blocked_files: blockedFiles,
5972
+ conflicts: formattedConflicts,
5973
+ recommendation: "coordinate_before_editing",
5626
5974
  message: `Claim not created. ${conflicts.length} conflict(s) detected. Coordinate before proceeding.`
5627
5975
  });
5628
5976
  }
5629
- const { claim } = await createClaim(db, {
5630
- session_id: input.session_id,
5631
- files,
5632
- symbols: input.symbols,
5633
- intent: input.intent,
5634
- scope: input.scope,
5635
- priority: input.priority
5636
- });
5637
- await logAuditEvent(db, {
5638
- session_id: input.session_id,
5639
- action: "claim_created",
5640
- entity_type: "claim",
5641
- entity_id: claim.id,
5642
- metadata: { files, intent: input.intent }
5643
- });
5644
- await saveMemory(db, input.session_id, {
5645
- category: "state",
5646
- key: `claim_${claim.id}`,
5647
- content: `Working on: ${input.intent}
5648
- Files: ${files.join(", ")}`,
5649
- priority: 60,
5650
- related_claim_id: claim.id,
5651
- metadata: { claim_id: claim.id, files }
5652
- });
5653
5977
  if (conflicts.length > 0) {
5978
+ if (!input.allow_conflicts) {
5979
+ const coordinationRequests = await createCoordinationRequests(db, {
5980
+ session_id: input.session_id,
5981
+ intent: input.intent,
5982
+ scope: input.scope,
5983
+ priority: input.priority
5984
+ }, conflicts);
5985
+ if (config.mode === "smart" && safeFiles.length > 0) {
5986
+ const claimId3 = await createTrackedClaim(db, {
5987
+ session_id: input.session_id,
5988
+ files: safeFiles,
5989
+ symbols: safeSymbols,
5990
+ intent: input.intent,
5991
+ scope: input.scope,
5992
+ priority: input.priority
5993
+ });
5994
+ return successResponse({
5995
+ success: true,
5996
+ claim_id: claimId3,
5997
+ status: "partial_claim_created",
5998
+ files,
5999
+ claimed_files: safeFiles,
6000
+ safe_files: safeFiles,
6001
+ blocked_files: blockedFiles,
6002
+ symbols: safeSymbols ?? [],
6003
+ conflicts: formattedConflicts,
6004
+ coordination_requests: coordinationRequests,
6005
+ recommendation: getCoordinationRecommendation(input.symbols, conflicts),
6006
+ message: `Claim created for safe files only. Coordinate before editing blocked files: [${blockedFiles.join(", ")}].`
6007
+ });
6008
+ }
6009
+ return successResponse({
6010
+ success: false,
6011
+ status: "waiting_for_coordination",
6012
+ files,
6013
+ claimed_files: [],
6014
+ safe_files: [],
6015
+ blocked_files: blockedFiles,
6016
+ symbols: input.symbols ?? [],
6017
+ conflicts: formattedConflicts,
6018
+ coordination_requests: coordinationRequests,
6019
+ recommendation: getCoordinationRecommendation(input.symbols, conflicts),
6020
+ message: `Claim not created. Waiting for coordination on blocked files: [${blockedFiles.join(", ")}].`
6021
+ });
6022
+ }
6023
+ const claimId2 = await createTrackedClaim(db, {
6024
+ session_id: input.session_id,
6025
+ files,
6026
+ symbols: input.symbols,
6027
+ intent: input.intent,
6028
+ scope: input.scope,
6029
+ priority: input.priority
6030
+ });
5654
6031
  return successResponse({
5655
6032
  success: true,
5656
- claim_id: claim.id,
6033
+ claim_id: claimId2,
5657
6034
  status: "created_with_conflicts",
5658
6035
  files,
6036
+ claimed_files: files,
6037
+ safe_files: safeFiles,
6038
+ blocked_files: blockedFiles,
5659
6039
  symbols: input.symbols ?? [],
5660
- conflicts: conflicts.map((c) => ({
5661
- session_name: c.session_name,
5662
- file: c.file_path,
5663
- intent: c.intent
5664
- })),
6040
+ conflicts: formattedConflicts,
5665
6041
  warning: `\u26A0\uFE0F ${conflicts.length} conflict(s) detected. Coordinate before proceeding.`
5666
6042
  });
5667
6043
  }
6044
+ const claimId = await createTrackedClaim(db, {
6045
+ session_id: input.session_id,
6046
+ files,
6047
+ symbols: input.symbols,
6048
+ intent: input.intent,
6049
+ scope: input.scope,
6050
+ priority: input.priority
6051
+ });
5668
6052
  return successResponse({
5669
6053
  success: true,
5670
- claim_id: claim.id,
6054
+ claim_id: claimId,
5671
6055
  status: "created",
5672
6056
  files,
6057
+ claimed_files: files,
6058
+ safe_files: files,
6059
+ blocked_files: [],
5673
6060
  symbols: input.symbols ?? [],
5674
6061
  intent: input.intent,
5675
6062
  message: "Claim created successfully."
@@ -5687,6 +6074,7 @@ Files: ${files.join(", ")}`,
5687
6074
  const excludeSelf = input.exclude_self ?? true;
5688
6075
  const excludeSessionId = excludeSelf ? input.session_id : void 0;
5689
6076
  const conflicts = await checkConflicts(db, input.files, excludeSessionId, input.symbols);
6077
+ const formattedConflicts = await formatConflicts(db, conflicts);
5690
6078
  if (conflicts.length === 0) {
5691
6079
  return successResponse({
5692
6080
  safe: true,
@@ -5707,11 +6095,7 @@ Files: ${files.join(", ")}`,
5707
6095
  recommendation: safeFiles.length > 0 ? "proceed_safe_only" : "abort",
5708
6096
  safe_files: safeFiles,
5709
6097
  blocked_files: Array.from(blockedFiles),
5710
- conflicts: conflicts.map((c) => ({
5711
- session_name: c.session_name,
5712
- file: c.file_path,
5713
- intent: c.intent
5714
- })),
6098
+ conflicts: formattedConflicts,
5715
6099
  message: safeFiles.length > 0 ? `Edit ONLY safe files: [${safeFiles.join(", ")}]. Skip blocked files.` : "All files blocked. Coordinate with other session(s)."
5716
6100
  });
5717
6101
  }
@@ -5746,6 +6130,7 @@ Files: ${files.join(", ")}`,
5746
6130
  if (claim.status !== "active") {
5747
6131
  return errorResponse(ERROR_CODES.CLAIM_ALREADY_RELEASED, `Claim already ${claim.status}`);
5748
6132
  }
6133
+ const notifications_sent = await notifyQueueOnClaimRelease(db, input.claim_id, input.session_id, claim.files);
5749
6134
  await releaseClaim(db, input.claim_id, {
5750
6135
  status,
5751
6136
  summary: input.summary
@@ -5762,6 +6147,7 @@ Files: ${files.join(", ")}`,
5762
6147
  success: true,
5763
6148
  claim_id: input.claim_id,
5764
6149
  files: claim.files,
6150
+ notifications_sent,
5765
6151
  message: `Claim ${status} released. Files now available.`
5766
6152
  });
5767
6153
  }
@@ -6234,4 +6620,4 @@ export {
6234
6620
  getMcpTools,
6235
6621
  handleMcpRequest
6236
6622
  };
6237
- //# sourceMappingURL=chunk-TFGXE3EI.js.map
6623
+ //# sourceMappingURL=chunk-UDJMG3TR.js.map