session-collab-mcp 0.5.4 → 0.6.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/cli.js +286 -377
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -4409,143 +4409,114 @@ async function listClaims(db, params = {}) {
|
|
|
4409
4409
|
}));
|
|
4410
4410
|
}
|
|
4411
4411
|
async function checkConflicts(db, files, excludeSessionId, symbols) {
|
|
4412
|
+
if (files.length === 0) {
|
|
4413
|
+
return [];
|
|
4414
|
+
}
|
|
4412
4415
|
const conflicts = [];
|
|
4413
4416
|
const symbolsByFile = /* @__PURE__ */ new Map();
|
|
4417
|
+
const allSymbolNames = /* @__PURE__ */ new Set();
|
|
4414
4418
|
if (symbols && symbols.length > 0) {
|
|
4415
4419
|
for (const sc of symbols) {
|
|
4416
4420
|
const existing = symbolsByFile.get(sc.file) ?? /* @__PURE__ */ new Set();
|
|
4417
4421
|
for (const sym of sc.symbols) {
|
|
4418
4422
|
existing.add(sym);
|
|
4423
|
+
allSymbolNames.add(sym);
|
|
4419
4424
|
}
|
|
4420
4425
|
symbolsByFile.set(sc.file, existing);
|
|
4421
4426
|
}
|
|
4422
4427
|
}
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
...r,
|
|
4454
|
-
conflict_level: "symbol"
|
|
4455
|
-
});
|
|
4456
|
-
}
|
|
4457
|
-
let fileClaimQuery = `
|
|
4458
|
-
SELECT
|
|
4459
|
-
c.id as claim_id,
|
|
4460
|
-
c.session_id,
|
|
4461
|
-
s.name as session_name,
|
|
4462
|
-
cf.file_path,
|
|
4463
|
-
c.intent,
|
|
4464
|
-
c.scope,
|
|
4465
|
-
c.created_at
|
|
4466
|
-
FROM claim_files cf
|
|
4467
|
-
JOIN claims c ON cf.claim_id = c.id
|
|
4468
|
-
JOIN sessions s ON c.session_id = s.id
|
|
4469
|
-
WHERE c.status = 'active'
|
|
4470
|
-
AND s.status = 'active'
|
|
4471
|
-
AND (cf.file_path = ? OR (cf.is_pattern = 1 AND ? GLOB cf.file_path))
|
|
4472
|
-
AND NOT EXISTS (
|
|
4473
|
-
SELECT 1 FROM claim_symbols cs WHERE cs.claim_id = c.id AND cs.file_path = cf.file_path
|
|
4474
|
-
)
|
|
4475
|
-
`;
|
|
4476
|
-
const fileClaimBindings = [filePath, filePath];
|
|
4477
|
-
if (excludeSessionId) {
|
|
4478
|
-
fileClaimQuery += " AND c.session_id != ?";
|
|
4479
|
-
fileClaimBindings.push(excludeSessionId);
|
|
4480
|
-
}
|
|
4481
|
-
const fileClaimResult = await db.prepare(fileClaimQuery).bind(...fileClaimBindings).all();
|
|
4482
|
-
for (const r of fileClaimResult.results) {
|
|
4483
|
-
conflicts.push({
|
|
4484
|
-
...r,
|
|
4485
|
-
conflict_level: "file"
|
|
4486
|
-
});
|
|
4487
|
-
}
|
|
4488
|
-
} else {
|
|
4489
|
-
let fileQuery = `
|
|
4490
|
-
SELECT
|
|
4491
|
-
c.id as claim_id,
|
|
4492
|
-
c.session_id,
|
|
4493
|
-
s.name as session_name,
|
|
4494
|
-
cf.file_path,
|
|
4495
|
-
c.intent,
|
|
4496
|
-
c.scope,
|
|
4497
|
-
c.created_at
|
|
4498
|
-
FROM claim_files cf
|
|
4499
|
-
JOIN claims c ON cf.claim_id = c.id
|
|
4500
|
-
JOIN sessions s ON c.session_id = s.id
|
|
4501
|
-
WHERE c.status = 'active'
|
|
4502
|
-
AND s.status = 'active'
|
|
4503
|
-
AND (cf.file_path = ? OR (cf.is_pattern = 1 AND ? GLOB cf.file_path))
|
|
4504
|
-
`;
|
|
4505
|
-
const fileBindings = [filePath, filePath];
|
|
4506
|
-
if (excludeSessionId) {
|
|
4507
|
-
fileQuery += " AND c.session_id != ?";
|
|
4508
|
-
fileBindings.push(excludeSessionId);
|
|
4509
|
-
}
|
|
4510
|
-
const fileResult = await db.prepare(fileQuery).bind(...fileBindings).all();
|
|
4511
|
-
for (const r of fileResult.results) {
|
|
4512
|
-
conflicts.push({
|
|
4513
|
-
...r,
|
|
4514
|
-
conflict_level: "file"
|
|
4515
|
-
});
|
|
4516
|
-
}
|
|
4517
|
-
let symbolOnlyQuery = `
|
|
4518
|
-
SELECT DISTINCT
|
|
4519
|
-
c.id as claim_id,
|
|
4520
|
-
c.session_id,
|
|
4521
|
-
s.name as session_name,
|
|
4522
|
-
cs.file_path,
|
|
4523
|
-
c.intent,
|
|
4524
|
-
c.scope,
|
|
4525
|
-
c.created_at,
|
|
4526
|
-
cs.symbol_name,
|
|
4527
|
-
cs.symbol_type
|
|
4528
|
-
FROM claim_symbols cs
|
|
4529
|
-
JOIN claims c ON cs.claim_id = c.id
|
|
4530
|
-
JOIN sessions s ON c.session_id = s.id
|
|
4531
|
-
WHERE c.status = 'active'
|
|
4532
|
-
AND s.status = 'active'
|
|
4533
|
-
AND cs.file_path = ?
|
|
4534
|
-
`;
|
|
4535
|
-
const symbolOnlyBindings = [filePath];
|
|
4536
|
-
if (excludeSessionId) {
|
|
4537
|
-
symbolOnlyQuery += " AND c.session_id != ?";
|
|
4538
|
-
symbolOnlyBindings.push(excludeSessionId);
|
|
4539
|
-
}
|
|
4540
|
-
const symbolOnlyResult = await db.prepare(symbolOnlyQuery).bind(...symbolOnlyBindings).all();
|
|
4541
|
-
for (const r of symbolOnlyResult.results) {
|
|
4542
|
-
conflicts.push({
|
|
4543
|
-
...r,
|
|
4544
|
-
conflict_level: "symbol"
|
|
4545
|
-
});
|
|
4546
|
-
}
|
|
4547
|
-
}
|
|
4428
|
+
const hasSymbols = symbolsByFile.size > 0;
|
|
4429
|
+
const sessionFilter = excludeSessionId ? " AND c.session_id != ?" : "";
|
|
4430
|
+
const fileConditions = files.map(() => "(cf.file_path = ? OR (cf.is_pattern = 1 AND ? GLOB cf.file_path))").join(" OR ");
|
|
4431
|
+
let fileQuery = `
|
|
4432
|
+
SELECT DISTINCT
|
|
4433
|
+
c.id as claim_id,
|
|
4434
|
+
c.session_id,
|
|
4435
|
+
s.name as session_name,
|
|
4436
|
+
cf.file_path,
|
|
4437
|
+
c.intent,
|
|
4438
|
+
c.scope,
|
|
4439
|
+
c.created_at,
|
|
4440
|
+
NULL as symbol_name,
|
|
4441
|
+
NULL as symbol_type,
|
|
4442
|
+
'file' as conflict_level
|
|
4443
|
+
FROM claim_files cf
|
|
4444
|
+
JOIN claims c ON cf.claim_id = c.id
|
|
4445
|
+
JOIN sessions s ON c.session_id = s.id
|
|
4446
|
+
WHERE c.status = 'active'
|
|
4447
|
+
AND s.status = 'active'
|
|
4448
|
+
AND (${fileConditions})
|
|
4449
|
+
${sessionFilter}
|
|
4450
|
+
`;
|
|
4451
|
+
if (hasSymbols) {
|
|
4452
|
+
fileQuery += `
|
|
4453
|
+
AND NOT EXISTS (
|
|
4454
|
+
SELECT 1 FROM claim_symbols cs
|
|
4455
|
+
WHERE cs.claim_id = c.id AND cs.file_path = cf.file_path
|
|
4456
|
+
)
|
|
4457
|
+
`;
|
|
4548
4458
|
}
|
|
4459
|
+
const fileBindings = files.flatMap((f) => [f, f]);
|
|
4460
|
+
if (excludeSessionId) {
|
|
4461
|
+
fileBindings.push(excludeSessionId);
|
|
4462
|
+
}
|
|
4463
|
+
const fileResult = await db.prepare(fileQuery).bind(...fileBindings).all();
|
|
4464
|
+
conflicts.push(...fileResult.results);
|
|
4465
|
+
const symbolFilePlaceholders = files.map(() => "?").join(",");
|
|
4466
|
+
let symbolQuery;
|
|
4467
|
+
let symbolBindings;
|
|
4468
|
+
if (hasSymbols && allSymbolNames.size > 0) {
|
|
4469
|
+
const symbolPlaceholders = Array.from(allSymbolNames).map(() => "?").join(",");
|
|
4470
|
+
symbolQuery = `
|
|
4471
|
+
SELECT DISTINCT
|
|
4472
|
+
c.id as claim_id,
|
|
4473
|
+
c.session_id,
|
|
4474
|
+
s.name as session_name,
|
|
4475
|
+
cs.file_path,
|
|
4476
|
+
c.intent,
|
|
4477
|
+
c.scope,
|
|
4478
|
+
c.created_at,
|
|
4479
|
+
cs.symbol_name,
|
|
4480
|
+
cs.symbol_type,
|
|
4481
|
+
'symbol' as conflict_level
|
|
4482
|
+
FROM claim_symbols cs
|
|
4483
|
+
JOIN claims c ON cs.claim_id = c.id
|
|
4484
|
+
JOIN sessions s ON c.session_id = s.id
|
|
4485
|
+
WHERE c.status = 'active'
|
|
4486
|
+
AND s.status = 'active'
|
|
4487
|
+
AND cs.file_path IN (${symbolFilePlaceholders})
|
|
4488
|
+
AND cs.symbol_name IN (${symbolPlaceholders})
|
|
4489
|
+
${sessionFilter}
|
|
4490
|
+
`;
|
|
4491
|
+
symbolBindings = [...files, ...Array.from(allSymbolNames)];
|
|
4492
|
+
} else {
|
|
4493
|
+
symbolQuery = `
|
|
4494
|
+
SELECT DISTINCT
|
|
4495
|
+
c.id as claim_id,
|
|
4496
|
+
c.session_id,
|
|
4497
|
+
s.name as session_name,
|
|
4498
|
+
cs.file_path,
|
|
4499
|
+
c.intent,
|
|
4500
|
+
c.scope,
|
|
4501
|
+
c.created_at,
|
|
4502
|
+
cs.symbol_name,
|
|
4503
|
+
cs.symbol_type,
|
|
4504
|
+
'symbol' as conflict_level
|
|
4505
|
+
FROM claim_symbols cs
|
|
4506
|
+
JOIN claims c ON cs.claim_id = c.id
|
|
4507
|
+
JOIN sessions s ON c.session_id = s.id
|
|
4508
|
+
WHERE c.status = 'active'
|
|
4509
|
+
AND s.status = 'active'
|
|
4510
|
+
AND cs.file_path IN (${symbolFilePlaceholders})
|
|
4511
|
+
${sessionFilter}
|
|
4512
|
+
`;
|
|
4513
|
+
symbolBindings = [...files];
|
|
4514
|
+
}
|
|
4515
|
+
if (excludeSessionId) {
|
|
4516
|
+
symbolBindings.push(excludeSessionId);
|
|
4517
|
+
}
|
|
4518
|
+
const symbolResult = await db.prepare(symbolQuery).bind(...symbolBindings).all();
|
|
4519
|
+
conflicts.push(...symbolResult.results);
|
|
4549
4520
|
const seen = /* @__PURE__ */ new Set();
|
|
4550
4521
|
return conflicts.filter((c) => {
|
|
4551
4522
|
const key = `${c.claim_id}:${c.file_path}:${c.symbol_name ?? ""}`;
|
|
@@ -4589,9 +4560,8 @@ async function listMessages(db, params) {
|
|
|
4589
4560
|
if (params.mark_as_read && messages.results.length > 0) {
|
|
4590
4561
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4591
4562
|
const ids = messages.results.map((m) => m.id);
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
}
|
|
4563
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
4564
|
+
await db.prepare(`UPDATE messages SET read_at = ? WHERE id IN (${placeholders}) AND read_at IS NULL`).bind(now, ...ids).run();
|
|
4595
4565
|
}
|
|
4596
4566
|
return messages.results;
|
|
4597
4567
|
}
|
|
@@ -4624,24 +4594,30 @@ async function listDecisions(db, params = {}) {
|
|
|
4624
4594
|
return result.results;
|
|
4625
4595
|
}
|
|
4626
4596
|
async function storeReferences(db, sessionId, references) {
|
|
4627
|
-
let stored = 0;
|
|
4628
|
-
let skipped = 0;
|
|
4629
4597
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4598
|
+
const statements = [];
|
|
4630
4599
|
for (const ref of references) {
|
|
4631
4600
|
for (const r of ref.references) {
|
|
4632
|
-
|
|
4633
|
-
|
|
4601
|
+
statements.push(
|
|
4602
|
+
db.prepare(
|
|
4634
4603
|
`INSERT OR IGNORE INTO symbol_references
|
|
4635
4604
|
(source_file, source_symbol, ref_file, ref_line, ref_context, session_id, created_at)
|
|
4636
4605
|
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
4637
|
-
).bind(ref.source_file, ref.source_symbol, r.file, r.line, r.context ?? null, sessionId, now)
|
|
4638
|
-
|
|
4639
|
-
} catch {
|
|
4640
|
-
skipped++;
|
|
4641
|
-
}
|
|
4606
|
+
).bind(ref.source_file, ref.source_symbol, r.file, r.line, r.context ?? null, sessionId, now)
|
|
4607
|
+
);
|
|
4642
4608
|
}
|
|
4643
4609
|
}
|
|
4644
|
-
|
|
4610
|
+
if (statements.length === 0) {
|
|
4611
|
+
return { stored: 0, skipped: 0 };
|
|
4612
|
+
}
|
|
4613
|
+
try {
|
|
4614
|
+
const results = await db.batch(statements);
|
|
4615
|
+
const stored = results.reduce((acc, r) => acc + r.meta.changes, 0);
|
|
4616
|
+
return { stored, skipped: statements.length - stored };
|
|
4617
|
+
} catch (err) {
|
|
4618
|
+
console.error("[storeReferences] Batch insert failed:", err);
|
|
4619
|
+
return { stored: 0, skipped: statements.length };
|
|
4620
|
+
}
|
|
4645
4621
|
}
|
|
4646
4622
|
async function getReferencesForSymbol(db, sourceFile, sourceSymbol) {
|
|
4647
4623
|
const result = await db.prepare(
|
|
@@ -4873,6 +4849,57 @@ function validateInput(schema, data) {
|
|
|
4873
4849
|
return { success: false, error: errors };
|
|
4874
4850
|
}
|
|
4875
4851
|
|
|
4852
|
+
// src/utils/response.ts
|
|
4853
|
+
var ERROR_CODES = {
|
|
4854
|
+
INVALID_INPUT: "INVALID_INPUT",
|
|
4855
|
+
SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
|
|
4856
|
+
SESSION_INVALID: "SESSION_INVALID",
|
|
4857
|
+
CLAIM_NOT_FOUND: "CLAIM_NOT_FOUND",
|
|
4858
|
+
CLAIM_ALREADY_RELEASED: "CLAIM_ALREADY_RELEASED",
|
|
4859
|
+
NOT_OWNER: "NOT_OWNER",
|
|
4860
|
+
TARGET_SESSION_INVALID: "TARGET_SESSION_INVALID"
|
|
4861
|
+
};
|
|
4862
|
+
function errorResponse(code, message, data) {
|
|
4863
|
+
return createToolResult(
|
|
4864
|
+
JSON.stringify({ error: code, message, ...data }),
|
|
4865
|
+
true
|
|
4866
|
+
);
|
|
4867
|
+
}
|
|
4868
|
+
function successResponse(data, prettyPrint = false) {
|
|
4869
|
+
return createToolResult(
|
|
4870
|
+
JSON.stringify(data, null, prettyPrint ? 2 : void 0)
|
|
4871
|
+
);
|
|
4872
|
+
}
|
|
4873
|
+
async function validateActiveSession(db, sessionId) {
|
|
4874
|
+
const session = await getSession(db, sessionId);
|
|
4875
|
+
if (!session) {
|
|
4876
|
+
return {
|
|
4877
|
+
valid: false,
|
|
4878
|
+
error: errorResponse(ERROR_CODES.SESSION_NOT_FOUND, "Session not found")
|
|
4879
|
+
};
|
|
4880
|
+
}
|
|
4881
|
+
if (session.status !== "active") {
|
|
4882
|
+
return {
|
|
4883
|
+
valid: false,
|
|
4884
|
+
error: errorResponse(ERROR_CODES.SESSION_INVALID, "Session not found or inactive.")
|
|
4885
|
+
};
|
|
4886
|
+
}
|
|
4887
|
+
return { valid: true, session };
|
|
4888
|
+
}
|
|
4889
|
+
async function validateSessionExists(db, sessionId) {
|
|
4890
|
+
const session = await getSession(db, sessionId);
|
|
4891
|
+
if (!session) {
|
|
4892
|
+
return {
|
|
4893
|
+
valid: false,
|
|
4894
|
+
error: errorResponse(ERROR_CODES.SESSION_NOT_FOUND, "Session not found")
|
|
4895
|
+
};
|
|
4896
|
+
}
|
|
4897
|
+
return { valid: true, session };
|
|
4898
|
+
}
|
|
4899
|
+
function validationError(message) {
|
|
4900
|
+
return errorResponse(ERROR_CODES.INVALID_INPUT, message);
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4876
4903
|
// src/mcp/tools/session.ts
|
|
4877
4904
|
var sessionTools = [
|
|
4878
4905
|
{
|
|
@@ -5029,10 +5056,7 @@ async function handleSessionTool(db, name, args, userId) {
|
|
|
5029
5056
|
case "collab_session_start": {
|
|
5030
5057
|
const validation = validateInput(sessionStartSchema, args);
|
|
5031
5058
|
if (!validation.success) {
|
|
5032
|
-
return
|
|
5033
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5034
|
-
true
|
|
5035
|
-
);
|
|
5059
|
+
return validationError(validation.error);
|
|
5036
5060
|
}
|
|
5037
5061
|
const input = validation.data;
|
|
5038
5062
|
await cleanupStaleSessions(db, 30);
|
|
@@ -5063,34 +5087,23 @@ async function handleSessionTool(db, name, args, userId) {
|
|
|
5063
5087
|
case "collab_session_end": {
|
|
5064
5088
|
const validation = validateInput(sessionEndSchema, args);
|
|
5065
5089
|
if (!validation.success) {
|
|
5066
|
-
return
|
|
5067
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5068
|
-
true
|
|
5069
|
-
);
|
|
5090
|
+
return validationError(validation.error);
|
|
5070
5091
|
}
|
|
5071
5092
|
const input = validation.data;
|
|
5072
|
-
const
|
|
5073
|
-
if (!
|
|
5074
|
-
return
|
|
5075
|
-
JSON.stringify({ error: "SESSION_NOT_FOUND", message: "Session not found" }),
|
|
5076
|
-
true
|
|
5077
|
-
);
|
|
5093
|
+
const sessionResult = await validateSessionExists(db, input.session_id);
|
|
5094
|
+
if (!sessionResult.valid) {
|
|
5095
|
+
return sessionResult.error;
|
|
5078
5096
|
}
|
|
5079
5097
|
await endSession(db, input.session_id, input.release_claims);
|
|
5080
|
-
return
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
})
|
|
5085
|
-
);
|
|
5098
|
+
return successResponse({
|
|
5099
|
+
success: true,
|
|
5100
|
+
message: `Session ended. All claims marked as ${input.release_claims === "complete" ? "completed" : "abandoned"}.`
|
|
5101
|
+
});
|
|
5086
5102
|
}
|
|
5087
5103
|
case "collab_session_list": {
|
|
5088
5104
|
const validation = validateInput(sessionListSchema, args);
|
|
5089
5105
|
if (!validation.success) {
|
|
5090
|
-
return
|
|
5091
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5092
|
-
true
|
|
5093
|
-
);
|
|
5106
|
+
return validationError(validation.error);
|
|
5094
5107
|
}
|
|
5095
5108
|
const input = validation.data;
|
|
5096
5109
|
const sessions = await listSessions(db, {
|
|
@@ -5134,10 +5147,7 @@ async function handleSessionTool(db, name, args, userId) {
|
|
|
5134
5147
|
case "collab_session_heartbeat": {
|
|
5135
5148
|
const validation = validateInput(sessionHeartbeatSchema, args);
|
|
5136
5149
|
if (!validation.success) {
|
|
5137
|
-
return
|
|
5138
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5139
|
-
true
|
|
5140
|
-
);
|
|
5150
|
+
return validationError(validation.error);
|
|
5141
5151
|
}
|
|
5142
5152
|
const input = validation.data;
|
|
5143
5153
|
const updated = await updateSessionHeartbeat(db, input.session_id, {
|
|
@@ -5145,41 +5155,27 @@ async function handleSessionTool(db, name, args, userId) {
|
|
|
5145
5155
|
todos: input.todos
|
|
5146
5156
|
});
|
|
5147
5157
|
if (!updated) {
|
|
5148
|
-
return
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
message: "Session not found or inactive. Please start a new session."
|
|
5152
|
-
}),
|
|
5153
|
-
true
|
|
5158
|
+
return errorResponse(
|
|
5159
|
+
ERROR_CODES.SESSION_NOT_FOUND,
|
|
5160
|
+
"Session not found or inactive. Please start a new session."
|
|
5154
5161
|
);
|
|
5155
5162
|
}
|
|
5156
|
-
return
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
})
|
|
5162
|
-
);
|
|
5163
|
+
return successResponse({
|
|
5164
|
+
success: true,
|
|
5165
|
+
message: "Heartbeat updated",
|
|
5166
|
+
status_synced: !!(input.current_task || input.todos)
|
|
5167
|
+
});
|
|
5163
5168
|
}
|
|
5164
5169
|
case "collab_status_update": {
|
|
5165
5170
|
const validation = validateInput(statusUpdateSchema, args);
|
|
5166
5171
|
if (!validation.success) {
|
|
5167
|
-
return
|
|
5168
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5169
|
-
true
|
|
5170
|
-
);
|
|
5172
|
+
return validationError(validation.error);
|
|
5171
5173
|
}
|
|
5172
5174
|
const input = validation.data;
|
|
5173
5175
|
const todos = input.todos;
|
|
5174
|
-
const
|
|
5175
|
-
if (!
|
|
5176
|
-
return
|
|
5177
|
-
JSON.stringify({
|
|
5178
|
-
error: "SESSION_INVALID",
|
|
5179
|
-
message: "Session not found or inactive."
|
|
5180
|
-
}),
|
|
5181
|
-
true
|
|
5182
|
-
);
|
|
5176
|
+
const sessionResult = await validateActiveSession(db, input.session_id);
|
|
5177
|
+
if (!sessionResult.valid) {
|
|
5178
|
+
return sessionResult.error;
|
|
5183
5179
|
}
|
|
5184
5180
|
await updateSessionStatus(db, input.session_id, {
|
|
5185
5181
|
current_task: input.current_task,
|
|
@@ -5194,34 +5190,24 @@ async function handleSessionTool(db, name, args, userId) {
|
|
|
5194
5190
|
percentage: Math.round(completed / todos.length * 100)
|
|
5195
5191
|
};
|
|
5196
5192
|
}
|
|
5197
|
-
return
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
})
|
|
5204
|
-
);
|
|
5193
|
+
return successResponse({
|
|
5194
|
+
success: true,
|
|
5195
|
+
message: "Status updated successfully.",
|
|
5196
|
+
current_task: input.current_task ?? null,
|
|
5197
|
+
progress
|
|
5198
|
+
});
|
|
5205
5199
|
}
|
|
5206
5200
|
case "collab_config": {
|
|
5207
5201
|
const validation = validateInput(configSchema, args);
|
|
5208
5202
|
if (!validation.success) {
|
|
5209
|
-
return
|
|
5210
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5211
|
-
true
|
|
5212
|
-
);
|
|
5203
|
+
return validationError(validation.error);
|
|
5213
5204
|
}
|
|
5214
5205
|
const input = validation.data;
|
|
5215
|
-
const
|
|
5216
|
-
if (!
|
|
5217
|
-
return
|
|
5218
|
-
JSON.stringify({
|
|
5219
|
-
error: "SESSION_INVALID",
|
|
5220
|
-
message: "Session not found or inactive."
|
|
5221
|
-
}),
|
|
5222
|
-
true
|
|
5223
|
-
);
|
|
5206
|
+
const sessionResult = await validateActiveSession(db, input.session_id);
|
|
5207
|
+
if (!sessionResult.valid) {
|
|
5208
|
+
return sessionResult.error;
|
|
5224
5209
|
}
|
|
5210
|
+
const { session } = sessionResult;
|
|
5225
5211
|
let currentConfig = DEFAULT_SESSION_CONFIG;
|
|
5226
5212
|
if (session.config) {
|
|
5227
5213
|
try {
|
|
@@ -5236,13 +5222,11 @@ async function handleSessionTool(db, name, args, userId) {
|
|
|
5236
5222
|
stale_threshold_hours: input.stale_threshold_hours ?? currentConfig.stale_threshold_hours
|
|
5237
5223
|
};
|
|
5238
5224
|
await updateSessionConfig(db, input.session_id, newConfig);
|
|
5239
|
-
return
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
})
|
|
5245
|
-
);
|
|
5225
|
+
return successResponse({
|
|
5226
|
+
success: true,
|
|
5227
|
+
message: "Configuration updated.",
|
|
5228
|
+
config: newConfig
|
|
5229
|
+
});
|
|
5246
5230
|
}
|
|
5247
5231
|
default:
|
|
5248
5232
|
return createToolResult(`Unknown session tool: ${name}`, true);
|
|
@@ -5394,22 +5378,13 @@ async function handleClaimTool(db, name, args) {
|
|
|
5394
5378
|
case "collab_claim": {
|
|
5395
5379
|
const validation = validateInput(claimCreateSchema, args);
|
|
5396
5380
|
if (!validation.success) {
|
|
5397
|
-
return
|
|
5398
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5399
|
-
true
|
|
5400
|
-
);
|
|
5381
|
+
return validationError(validation.error);
|
|
5401
5382
|
}
|
|
5402
5383
|
const { session_id: sessionId, files, symbols, intent, scope = "medium" } = validation.data;
|
|
5403
5384
|
const hasSymbols = symbols && symbols.length > 0;
|
|
5404
|
-
const
|
|
5405
|
-
if (!
|
|
5406
|
-
return
|
|
5407
|
-
JSON.stringify({
|
|
5408
|
-
error: "SESSION_INVALID",
|
|
5409
|
-
message: "Session not found or inactive. Please start a new session."
|
|
5410
|
-
}),
|
|
5411
|
-
true
|
|
5412
|
-
);
|
|
5385
|
+
const sessionResult = await validateActiveSession(db, sessionId);
|
|
5386
|
+
if (!sessionResult.valid) {
|
|
5387
|
+
return sessionResult.error;
|
|
5413
5388
|
}
|
|
5414
5389
|
const allFiles = new Set(files ?? []);
|
|
5415
5390
|
if (hasSymbols) {
|
|
@@ -5473,10 +5448,7 @@ async function handleClaimTool(db, name, args) {
|
|
|
5473
5448
|
case "collab_check": {
|
|
5474
5449
|
const validation = validateInput(claimCheckSchema, args);
|
|
5475
5450
|
if (!validation.success) {
|
|
5476
|
-
return
|
|
5477
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5478
|
-
true
|
|
5479
|
-
);
|
|
5451
|
+
return validationError(validation.error);
|
|
5480
5452
|
}
|
|
5481
5453
|
const { files, symbols, session_id: sessionId } = validation.data;
|
|
5482
5454
|
let hasInProgressTodo = false;
|
|
@@ -5625,20 +5597,14 @@ async function handleClaimTool(db, name, args) {
|
|
|
5625
5597
|
case "collab_release": {
|
|
5626
5598
|
const validation = validateInput(claimReleaseSchema, args);
|
|
5627
5599
|
if (!validation.success) {
|
|
5628
|
-
return
|
|
5629
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5630
|
-
true
|
|
5631
|
-
);
|
|
5600
|
+
return validationError(validation.error);
|
|
5632
5601
|
}
|
|
5633
5602
|
const { session_id: sessionId, claim_id: claimId, status, summary, force } = validation.data;
|
|
5634
5603
|
const claim = await getClaim(db, claimId);
|
|
5635
5604
|
if (!claim) {
|
|
5636
|
-
return
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
message: "Claim not found. It may have already been released."
|
|
5640
|
-
}),
|
|
5641
|
-
true
|
|
5605
|
+
return errorResponse(
|
|
5606
|
+
ERROR_CODES.CLAIM_NOT_FOUND,
|
|
5607
|
+
"Claim not found. It may have already been released."
|
|
5642
5608
|
);
|
|
5643
5609
|
}
|
|
5644
5610
|
if (claim.session_id !== sessionId) {
|
|
@@ -5673,12 +5639,9 @@ async function handleClaimTool(db, name, args) {
|
|
|
5673
5639
|
}
|
|
5674
5640
|
}
|
|
5675
5641
|
if (claim.status !== "active") {
|
|
5676
|
-
return
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
message: `Claim was already ${claim.status}.`
|
|
5680
|
-
}),
|
|
5681
|
-
true
|
|
5642
|
+
return errorResponse(
|
|
5643
|
+
ERROR_CODES.CLAIM_ALREADY_RELEASED,
|
|
5644
|
+
`Claim was already ${claim.status}.`
|
|
5682
5645
|
);
|
|
5683
5646
|
}
|
|
5684
5647
|
const isOwnClaim = claim.session_id === sessionId;
|
|
@@ -5696,33 +5659,24 @@ async function handleClaimTool(db, name, args) {
|
|
|
5696
5659
|
case "collab_claims_list": {
|
|
5697
5660
|
const validation = validateInput(claimListSchema, args);
|
|
5698
5661
|
if (!validation.success) {
|
|
5699
|
-
return
|
|
5700
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5701
|
-
true
|
|
5702
|
-
);
|
|
5662
|
+
return validationError(validation.error);
|
|
5703
5663
|
}
|
|
5704
5664
|
const { session_id, status = "active", project_root } = validation.data;
|
|
5705
5665
|
const claims = await listClaims(db, { session_id, status, project_root });
|
|
5706
|
-
return
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
total: claims.length
|
|
5721
|
-
},
|
|
5722
|
-
null,
|
|
5723
|
-
2
|
|
5724
|
-
)
|
|
5725
|
-
);
|
|
5666
|
+
return successResponse({
|
|
5667
|
+
claims: claims.map((c) => ({
|
|
5668
|
+
id: c.id,
|
|
5669
|
+
session_id: c.session_id,
|
|
5670
|
+
session_name: c.session_name,
|
|
5671
|
+
files: c.files,
|
|
5672
|
+
intent: c.intent,
|
|
5673
|
+
scope: c.scope,
|
|
5674
|
+
status: c.status,
|
|
5675
|
+
created_at: c.created_at,
|
|
5676
|
+
completed_summary: c.completed_summary
|
|
5677
|
+
})),
|
|
5678
|
+
total: claims.length
|
|
5679
|
+
}, true);
|
|
5726
5680
|
}
|
|
5727
5681
|
default:
|
|
5728
5682
|
return createToolResult(`Unknown claim tool: ${name}`, true);
|
|
@@ -5781,31 +5735,19 @@ async function handleMessageTool(db, name, args) {
|
|
|
5781
5735
|
case "collab_message_send": {
|
|
5782
5736
|
const validation = validateInput(messageSendSchema, args);
|
|
5783
5737
|
if (!validation.success) {
|
|
5784
|
-
return
|
|
5785
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5786
|
-
true
|
|
5787
|
-
);
|
|
5738
|
+
return validationError(validation.error);
|
|
5788
5739
|
}
|
|
5789
5740
|
const input = validation.data;
|
|
5790
|
-
const
|
|
5791
|
-
if (!
|
|
5792
|
-
return
|
|
5793
|
-
JSON.stringify({
|
|
5794
|
-
error: "SESSION_INVALID",
|
|
5795
|
-
message: "Your session is not active."
|
|
5796
|
-
}),
|
|
5797
|
-
true
|
|
5798
|
-
);
|
|
5741
|
+
const senderResult = await validateActiveSession(db, input.from_session_id);
|
|
5742
|
+
if (!senderResult.valid) {
|
|
5743
|
+
return errorResponse(ERROR_CODES.SESSION_INVALID, "Your session is not active.");
|
|
5799
5744
|
}
|
|
5800
5745
|
if (input.to_session_id) {
|
|
5801
|
-
const
|
|
5802
|
-
if (!
|
|
5803
|
-
return
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
message: "Target session not found or inactive."
|
|
5807
|
-
}),
|
|
5808
|
-
true
|
|
5746
|
+
const targetResult = await validateActiveSession(db, input.to_session_id);
|
|
5747
|
+
if (!targetResult.valid) {
|
|
5748
|
+
return errorResponse(
|
|
5749
|
+
ERROR_CODES.TARGET_SESSION_INVALID,
|
|
5750
|
+
"Target session not found or inactive."
|
|
5809
5751
|
);
|
|
5810
5752
|
}
|
|
5811
5753
|
}
|
|
@@ -5814,22 +5756,17 @@ async function handleMessageTool(db, name, args) {
|
|
|
5814
5756
|
to_session_id: input.to_session_id,
|
|
5815
5757
|
content: input.content
|
|
5816
5758
|
});
|
|
5817
|
-
return
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
})
|
|
5824
|
-
);
|
|
5759
|
+
return successResponse({
|
|
5760
|
+
success: true,
|
|
5761
|
+
message_id: message.id,
|
|
5762
|
+
sent_to: input.to_session_id ?? "all sessions (broadcast)",
|
|
5763
|
+
message: "Message sent successfully."
|
|
5764
|
+
});
|
|
5825
5765
|
}
|
|
5826
5766
|
case "collab_message_list": {
|
|
5827
5767
|
const validation = validateInput(messageListSchema, args);
|
|
5828
5768
|
if (!validation.success) {
|
|
5829
|
-
return
|
|
5830
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5831
|
-
true
|
|
5832
|
-
);
|
|
5769
|
+
return validationError(validation.error);
|
|
5833
5770
|
}
|
|
5834
5771
|
const input = validation.data;
|
|
5835
5772
|
const unreadOnly = input.unread_only ?? true;
|
|
@@ -5840,30 +5777,22 @@ async function handleMessageTool(db, name, args) {
|
|
|
5840
5777
|
mark_as_read: markAsRead
|
|
5841
5778
|
});
|
|
5842
5779
|
if (messages.length === 0) {
|
|
5843
|
-
return
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
})
|
|
5848
|
-
);
|
|
5780
|
+
return successResponse({
|
|
5781
|
+
messages: [],
|
|
5782
|
+
message: unreadOnly ? "No unread messages." : "No messages."
|
|
5783
|
+
});
|
|
5849
5784
|
}
|
|
5850
|
-
return
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
marked_as_read: markAsRead
|
|
5862
|
-
},
|
|
5863
|
-
null,
|
|
5864
|
-
2
|
|
5865
|
-
)
|
|
5866
|
-
);
|
|
5785
|
+
return successResponse({
|
|
5786
|
+
messages: messages.map((m) => ({
|
|
5787
|
+
id: m.id,
|
|
5788
|
+
from_session_id: m.from_session_id,
|
|
5789
|
+
content: m.content,
|
|
5790
|
+
created_at: m.created_at,
|
|
5791
|
+
is_broadcast: m.to_session_id === null
|
|
5792
|
+
})),
|
|
5793
|
+
total: messages.length,
|
|
5794
|
+
marked_as_read: markAsRead
|
|
5795
|
+
}, true);
|
|
5867
5796
|
}
|
|
5868
5797
|
default:
|
|
5869
5798
|
return createToolResult(`Unknown message tool: ${name}`, true);
|
|
@@ -5923,21 +5852,12 @@ async function handleDecisionTool(db, name, args) {
|
|
|
5923
5852
|
case "collab_decision_add": {
|
|
5924
5853
|
const validation = validateInput(decisionAddSchema, args);
|
|
5925
5854
|
if (!validation.success) {
|
|
5926
|
-
return
|
|
5927
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5928
|
-
true
|
|
5929
|
-
);
|
|
5855
|
+
return validationError(validation.error);
|
|
5930
5856
|
}
|
|
5931
5857
|
const input = validation.data;
|
|
5932
|
-
const
|
|
5933
|
-
if (!
|
|
5934
|
-
return
|
|
5935
|
-
JSON.stringify({
|
|
5936
|
-
error: "SESSION_INVALID",
|
|
5937
|
-
message: "Session not found or inactive."
|
|
5938
|
-
}),
|
|
5939
|
-
true
|
|
5940
|
-
);
|
|
5858
|
+
const sessionResult = await validateActiveSession(db, input.session_id);
|
|
5859
|
+
if (!sessionResult.valid) {
|
|
5860
|
+
return sessionResult.error;
|
|
5941
5861
|
}
|
|
5942
5862
|
const decision = await addDecision(db, {
|
|
5943
5863
|
session_id: input.session_id,
|
|
@@ -5945,43 +5865,32 @@ async function handleDecisionTool(db, name, args) {
|
|
|
5945
5865
|
title: input.title,
|
|
5946
5866
|
description: input.description
|
|
5947
5867
|
});
|
|
5948
|
-
return
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
})
|
|
5954
|
-
);
|
|
5868
|
+
return successResponse({
|
|
5869
|
+
success: true,
|
|
5870
|
+
decision_id: decision.id,
|
|
5871
|
+
message: "Decision recorded successfully."
|
|
5872
|
+
});
|
|
5955
5873
|
}
|
|
5956
5874
|
case "collab_decision_list": {
|
|
5957
5875
|
const validation = validateInput(decisionListSchema, args);
|
|
5958
5876
|
if (!validation.success) {
|
|
5959
|
-
return
|
|
5960
|
-
JSON.stringify({ error: "INVALID_INPUT", message: validation.error }),
|
|
5961
|
-
true
|
|
5962
|
-
);
|
|
5877
|
+
return validationError(validation.error);
|
|
5963
5878
|
}
|
|
5964
5879
|
const input = validation.data;
|
|
5965
5880
|
const decisions = await listDecisions(db, {
|
|
5966
5881
|
category: input.category,
|
|
5967
5882
|
limit: input.limit ?? 20
|
|
5968
5883
|
});
|
|
5969
|
-
return
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
total: decisions.length
|
|
5980
|
-
},
|
|
5981
|
-
null,
|
|
5982
|
-
2
|
|
5983
|
-
)
|
|
5984
|
-
);
|
|
5884
|
+
return successResponse({
|
|
5885
|
+
decisions: decisions.map((d) => ({
|
|
5886
|
+
id: d.id,
|
|
5887
|
+
category: d.category,
|
|
5888
|
+
title: d.title,
|
|
5889
|
+
description: d.description,
|
|
5890
|
+
created_at: d.created_at
|
|
5891
|
+
})),
|
|
5892
|
+
total: decisions.length
|
|
5893
|
+
}, true);
|
|
5985
5894
|
}
|
|
5986
5895
|
default:
|
|
5987
5896
|
return createToolResult(`Unknown decision tool: ${name}`, true);
|
|
@@ -6842,14 +6751,14 @@ async function main() {
|
|
|
6842
6751
|
break;
|
|
6843
6752
|
}
|
|
6844
6753
|
default: {
|
|
6845
|
-
const
|
|
6846
|
-
console.log(
|
|
6754
|
+
const errorResponse2 = jsonRpcError(id, -32601, `Method not found: ${method}`);
|
|
6755
|
+
console.log(errorResponse2);
|
|
6847
6756
|
}
|
|
6848
6757
|
}
|
|
6849
6758
|
} catch (error) {
|
|
6850
6759
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
6851
|
-
const
|
|
6852
|
-
console.log(
|
|
6760
|
+
const errorResponse2 = jsonRpcError(null, -32700, `Parse error: ${errorMessage}`);
|
|
6761
|
+
console.log(errorResponse2);
|
|
6853
6762
|
}
|
|
6854
6763
|
});
|
|
6855
6764
|
rl.on("close", () => {
|