fix: v2.0.1 release — fix broken installs, CI, security, and docs

Critical fixes:
- npm postinstall.js: BINARY_VERSION '1.1.3' → '2.0.1' (every install was 404ing)
- npm package name: corrected error messages to 'vestige-mcp-server'
- README: npm install command pointed to wrong package
- MSRV: bumped from 1.85 to 1.91 (uses floor_char_boundary from 1.91)
- CI: removed stale 'develop' branch from test.yml triggers

Security hardening:
- CSP: restricted connect-src from wildcard 'ws: wss:' to localhost-only
- Added X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy headers
- Added frame-ancestors 'none', base-uri 'self', form-action 'self' to CSP
- Capped retention_distribution endpoint from 10k to 1k nodes
- Added debug logging for WebSocket connections without Origin header

Maintenance:
- All clippy warnings fixed (58 total: redundant closures, collapsible ifs, no-op casts)
- All versions harmonized to 2.0.1 across Cargo.toml and package.json
- CLAUDE.md updated to match v2.0.1 (21 tools, 29 modules, 1238 tests)
- docs/CLAUDE-SETUP.md updated deprecated function names
- License corrected to AGPL-3.0-only in root package.json

1,238 tests passing, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam Valladares 2026-03-01 20:20:14 -06:00
parent b03df324da
commit c6090dc2ba
51 changed files with 343 additions and 490 deletions

View file

@ -72,10 +72,10 @@ pub async fn execute(
if let Some(ref memory_id) = args.memory_id {
// Per-memory mode: state transitions for a specific memory
execute_per_memory(&storage, memory_id, limit)
execute_per_memory(storage, memory_id, limit)
} else {
// System-wide mode: consolidations + recent transitions
execute_system_wide(&storage, limit)
execute_system_wide(storage, limit)
}
}

View file

@ -204,7 +204,7 @@ async fn execute_remember_decision(
// Build content with structured format (ADR-like)
let mut content = format!(
"# Decision: {}\n\n## Context\n\n{}\n\n## Decision\n\n{}",
&decision[..decision.len().min(50)],
&decision[..decision.floor_char_boundary(50)],
rationale,
decision
);

View file

@ -219,7 +219,7 @@ pub async fn execute(
.map(|n| {
let c = n.content.replace('\n', " ");
if c.len() > 120 {
format!("{}...", &c[..120])
format!("{}...", &c[..c.floor_char_boundary(120)])
} else {
c
}

View file

@ -96,7 +96,7 @@ pub async fn execute(
if intent_result.confidence > 0.5 {
let intent_tag = format!("intent:{:?}", intent_result.primary_intent);
let intent_tag = if intent_tag.len() > 50 {
format!("{}...", &intent_tag[..47])
format!("{}...", &intent_tag[..intent_tag.floor_char_boundary(47)])
} else {
intent_tag
};

View file

@ -297,7 +297,7 @@ async fn execute_set(
if intent_result.confidence > 0.5 {
let intent_tag = format!("intent:{:?}", intent_result.primary_intent);
let intent_tag = if intent_tag.len() > 50 {
format!("{}...", &intent_tag[..47])
format!("{}...", &intent_tag[..intent_tag.floor_char_boundary(47)])
} else {
intent_tag
};

View file

@ -249,7 +249,7 @@ pub async fn execute_system_status(
let last_dream = storage.get_last_dream().ok().flatten();
let saves_since_last_dream = match &last_dream {
Some(dt) => storage.count_memories_since(*dt).unwrap_or(0),
None => stats.total_nodes as i64,
None => stats.total_nodes,
};
let last_backup = Storage::get_last_backup_timestamp();

View file

@ -37,8 +37,10 @@ pub mod session_context;
pub mod health;
pub mod graph;
// Deprecated tools - kept for internal backwards compatibility
// These modules are intentionally unused in the public API
// Deprecated/internal tools — not advertised in the public MCP tools/list,
// but some functions are actively dispatched for backwards compatibility
// and internal cognitive operations. #[allow(dead_code)] suppresses warnings
// for the unused schema/struct items within these modules.
#[allow(dead_code)]
pub mod checkpoint;
#[allow(dead_code)]

View file

@ -218,7 +218,7 @@ pub async fn execute(
let last_dream = storage.get_last_dream().ok().flatten();
let saves_since_last_dream = match &last_dream {
Some(dt) => storage.count_memories_since(*dt).unwrap_or(0),
None => stats.total_nodes as i64,
None => stats.total_nodes,
};
let last_backup = Storage::get_last_backup_timestamp();
let now = Utc::now();
@ -333,8 +333,8 @@ pub async fn execute(
// ====================================================================
// 5. Codebase patterns/decisions (if codebase specified)
// ====================================================================
if let Some(ref ctx) = args.context {
if let Some(ref codebase) = ctx.codebase {
if let Some(ref ctx) = args.context
&& let Some(ref codebase) = ctx.codebase {
let codebase_tag = format!("codebase:{}", codebase);
let mut cb_lines: Vec<String> = Vec::new();
@ -368,7 +368,6 @@ pub async fn execute(
context_parts.push(format!("**Codebase ({}):**\n{}", codebase, cb_lines.join("\n")));
}
}
}
// ====================================================================
// 6. Assemble final response
@ -404,11 +403,10 @@ fn check_intention_triggered(
match trigger.trigger_type.as_deref() {
Some("time") => {
if let Some(ref at) = trigger.at {
if let Ok(trigger_time) = DateTime::parse_from_rfc3339(at) {
if let Some(ref at) = trigger.at
&& let Ok(trigger_time) = DateTime::parse_from_rfc3339(at) {
return trigger_time.with_timezone(&Utc) <= now;
}
}
if let Some(mins) = trigger.in_minutes {
let trigger_time = intention.created_at + Duration::minutes(mins);
return trigger_time <= now;
@ -418,29 +416,25 @@ fn check_intention_triggered(
Some("context") => {
// Check codebase match
if let (Some(trigger_cb), Some(current_cb)) = (&trigger.codebase, &ctx.codebase)
{
if current_cb
&& current_cb
.to_lowercase()
.contains(&trigger_cb.to_lowercase())
{
return true;
}
}
// Check file pattern match
if let (Some(pattern), Some(file)) = (&trigger.file_pattern, &ctx.file) {
if file.contains(pattern.as_str()) {
if let (Some(pattern), Some(file)) = (&trigger.file_pattern, &ctx.file)
&& file.contains(pattern.as_str()) {
return true;
}
}
// Check topic match
if let (Some(topic), Some(topics)) = (&trigger.topic, &ctx.topics) {
if topics
if let (Some(topic), Some(topics)) = (&trigger.topic, &ctx.topics)
&& topics
.iter()
.any(|t| t.to_lowercase().contains(&topic.to_lowercase()))
{
return true;
}
}
false
}
_ => false,

View file

@ -165,7 +165,7 @@ pub async fn execute(
let intent_tag = format!("intent:{:?}", intent_result.primary_intent);
// Truncate long intent tags
let intent_tag = if intent_tag.len() > 50 {
format!("{}...", &intent_tag[..47])
format!("{}...", &intent_tag[..intent_tag.floor_char_boundary(47)])
} else {
intent_tag
};
@ -338,7 +338,7 @@ async fn execute_batch(
if intent_result.confidence > 0.5 {
let intent_tag = format!("intent:{:?}", intent_result.primary_intent);
let intent_tag = if intent_tag.len() > 50 {
format!("{}...", &intent_tag[..47])
format!("{}...", &intent_tag[..intent_tag.floor_char_boundary(47)])
} else {
intent_tag
};