handoff-mcp-server 0.24.5 → 0.24.6
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/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/package.json +1 -1
- package/src/mcp/handlers/save_context.rs +8 -3
- package/src/mcp/handlers/update_session.rs +6 -4
- package/src/storage/sessions.rs +39 -11
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "handoff-mcp-server",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.6",
|
|
4
4
|
"description": "MCP server that gives AI coding agents persistent memory across sessions",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AlphaElements <66808803+alphaelements@users.noreply.github.com>",
|
|
@@ -130,11 +130,16 @@ pub fn handle(arguments: &Value) -> Result<String> {
|
|
|
130
130
|
if let Some(active_session) = target {
|
|
131
131
|
let sid = active_session.id.clone().unwrap_or_default();
|
|
132
132
|
if keep_active {
|
|
133
|
-
let updated_path =
|
|
133
|
+
let updated_path =
|
|
134
|
+
update_active_session(&sessions_dir, &sid, &handoff_updates, Some(arguments))?;
|
|
134
135
|
(0, updated_path, Some(sid))
|
|
135
136
|
} else {
|
|
136
|
-
let closed_path =
|
|
137
|
-
|
|
137
|
+
let closed_path = update_and_close_active_session(
|
|
138
|
+
&sessions_dir,
|
|
139
|
+
&sid,
|
|
140
|
+
&handoff_updates,
|
|
141
|
+
Some(arguments),
|
|
142
|
+
)?;
|
|
138
143
|
(
|
|
139
144
|
if closed_path.is_some() { 1 } else { 0 },
|
|
140
145
|
closed_path,
|
|
@@ -153,11 +153,13 @@ pub fn handle(arguments: &Value) -> Result<String> {
|
|
|
153
153
|
Ok(msg)
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
fn truncate(s: &str,
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
fn truncate(s: &str, max_chars: usize) -> String {
|
|
157
|
+
let mut chars = s.chars();
|
|
158
|
+
let truncated: String = chars.by_ref().take(max_chars).collect();
|
|
159
|
+
if chars.next().is_some() {
|
|
160
|
+
format!("{truncated}...")
|
|
159
161
|
} else {
|
|
160
|
-
|
|
162
|
+
truncated
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
|
package/src/storage/sessions.rs
CHANGED
|
@@ -384,18 +384,37 @@ pub fn read_latest_closed_session(sessions_dir: &Path) -> Result<Option<SessionD
|
|
|
384
384
|
Ok(sessions.into_iter().last())
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
fn apply_session_updates(
|
|
387
|
+
fn apply_session_updates(
|
|
388
|
+
data: &mut SessionData,
|
|
389
|
+
updates: &SessionData,
|
|
390
|
+
provided_keys: Option<&Value>,
|
|
391
|
+
) {
|
|
388
392
|
data.summary = updates.summary.clone();
|
|
389
393
|
data.ended_at = updates.ended_at.clone();
|
|
390
394
|
data.branch = updates.branch.clone();
|
|
391
395
|
data.commit = updates.commit.clone();
|
|
392
396
|
data.dirty_files = updates.dirty_files.clone();
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
397
|
+
|
|
398
|
+
let was_provided = |key: &str| provided_keys.and_then(|v| v.get(key)).is_some();
|
|
399
|
+
|
|
400
|
+
if was_provided("decisions") {
|
|
401
|
+
data.decisions = updates.decisions.clone();
|
|
402
|
+
}
|
|
403
|
+
if was_provided("blockers") {
|
|
404
|
+
data.blockers = updates.blockers.clone();
|
|
405
|
+
}
|
|
406
|
+
if was_provided("checklist") {
|
|
407
|
+
data.checklist = updates.checklist.clone();
|
|
408
|
+
}
|
|
409
|
+
if was_provided("handoff_notes") {
|
|
410
|
+
data.handoff_notes = updates.handoff_notes.clone();
|
|
411
|
+
}
|
|
412
|
+
if was_provided("references") {
|
|
413
|
+
data.references = updates.references.clone();
|
|
414
|
+
}
|
|
415
|
+
if was_provided("context_pointers") {
|
|
416
|
+
data.context_pointers = updates.context_pointers.clone();
|
|
417
|
+
}
|
|
399
418
|
if updates.environment.is_some() {
|
|
400
419
|
data.environment = updates.environment.clone();
|
|
401
420
|
}
|
|
@@ -405,7 +424,7 @@ fn apply_session_updates(data: &mut SessionData, updates: &SessionData) {
|
|
|
405
424
|
if updates.label.is_some() {
|
|
406
425
|
data.label = updates.label.clone();
|
|
407
426
|
}
|
|
408
|
-
if !updates.related_task_ids.is_empty() {
|
|
427
|
+
if was_provided("related_task_ids") && !updates.related_task_ids.is_empty() {
|
|
409
428
|
data.related_task_ids = updates.related_task_ids.clone();
|
|
410
429
|
}
|
|
411
430
|
}
|
|
@@ -415,6 +434,7 @@ fn find_and_update_active_session(
|
|
|
415
434
|
session_id: &str,
|
|
416
435
|
updates: &SessionData,
|
|
417
436
|
transition_to: Option<&str>,
|
|
437
|
+
provided_keys: Option<&Value>,
|
|
418
438
|
) -> Result<Option<PathBuf>> {
|
|
419
439
|
let suffix = ".active.json";
|
|
420
440
|
|
|
@@ -464,7 +484,7 @@ fn find_and_update_active_session(
|
|
|
464
484
|
let mut data: SessionData = serde_json::from_str(&content)
|
|
465
485
|
.with_context(|| format!("Failed to parse session: {}", path.display()))?;
|
|
466
486
|
|
|
467
|
-
apply_session_updates(&mut data, updates);
|
|
487
|
+
apply_session_updates(&mut data, updates, provided_keys);
|
|
468
488
|
|
|
469
489
|
let updated_content =
|
|
470
490
|
serde_json::to_string_pretty(&data).context("Failed to serialize session")?;
|
|
@@ -495,16 +515,24 @@ pub fn update_and_close_active_session(
|
|
|
495
515
|
sessions_dir: &Path,
|
|
496
516
|
session_id: &str,
|
|
497
517
|
updates: &SessionData,
|
|
518
|
+
provided_keys: Option<&Value>,
|
|
498
519
|
) -> Result<Option<PathBuf>> {
|
|
499
|
-
find_and_update_active_session(
|
|
520
|
+
find_and_update_active_session(
|
|
521
|
+
sessions_dir,
|
|
522
|
+
session_id,
|
|
523
|
+
updates,
|
|
524
|
+
Some("closed"),
|
|
525
|
+
provided_keys,
|
|
526
|
+
)
|
|
500
527
|
}
|
|
501
528
|
|
|
502
529
|
pub fn update_active_session(
|
|
503
530
|
sessions_dir: &Path,
|
|
504
531
|
session_id: &str,
|
|
505
532
|
updates: &SessionData,
|
|
533
|
+
provided_keys: Option<&Value>,
|
|
506
534
|
) -> Result<Option<PathBuf>> {
|
|
507
|
-
find_and_update_active_session(sessions_dir, session_id, updates, None)
|
|
535
|
+
find_and_update_active_session(sessions_dir, session_id, updates, None, provided_keys)
|
|
508
536
|
}
|
|
509
537
|
|
|
510
538
|
pub fn read_session_by_id(sessions_dir: &Path, session_id: &str) -> Result<Option<SessionData>> {
|