Skip to content

Commit 4f1cc74

Browse files
committed
Merge main (cargo fmt fix) into dev
# Conflicts: # mcp/integrate-tests/tests/packaging_smoke.rs
2 parents 7986e3e + 34228f9 commit 4f1cc74

10 files changed

Lines changed: 119 additions & 32 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use std::fs;
2+
3+
#[cfg(unix)]
4+
use std::os::unix::fs::PermissionsExt;
5+
6+
use tnmsm_integrate_tests::{
7+
create_staged_package_root, install_packaged_mcp_container, real_env_test_skip_reason,
8+
run_mcp_with_env, workspace_root,
9+
};
10+
11+
#[test]
12+
fn packaging_smoke_covers_release_binary_and_global_install() {
13+
if let Some(reason) = real_env_test_skip_reason() {
14+
eprintln!("skipping packaging smoke: {reason}");
15+
return;
16+
}
17+
18+
let staged = create_staged_package_root();
19+
let package_root = staged.package_root.to_string_lossy().into_owned();
20+
let workspace_root_dir = workspace_root().to_string_lossy().into_owned();
21+
22+
let assemble = run_mcp_with_env(
23+
&["assemble-npm", "--profile", "release"],
24+
&workspace_root(),
25+
&[
26+
("TNMSM_NPM_PACKAGE_ROOT", package_root.as_str()),
27+
("TNMSM_WORKSPACE_ROOT", workspace_root_dir.as_str()),
28+
],
29+
);
30+
assemble.assert_success("tnmsm assemble-npm --profile release");
31+
32+
assert!(
33+
staged.linux_binary.is_file(),
34+
"expected hydrated linux binary at {}",
35+
staged.linux_binary.display()
36+
);
37+
38+
#[cfg(unix)]
39+
{
40+
let mode = fs::metadata(&staged.linux_binary)
41+
.unwrap_or_else(|error| panic!("failed to stat {}: {error}", staged.linux_binary.display()))
42+
.permissions()
43+
.mode();
44+
assert!(
45+
mode & 0o111 != 0,
46+
"expected {} to be executable, mode was {:o}",
47+
staged.linux_binary.display(),
48+
mode
49+
);
50+
}
51+
52+
let container = install_packaged_mcp_container();
53+
54+
let initialize = container
55+
.exec(r#"printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | tnmsm"#);
56+
initialize.assert_success("global tnmsm initialize");
57+
for expected in [
58+
"\"jsonrpc\":\"2.0\"",
59+
"\"protocolVersion\":\"2024-11-05\"",
60+
"\"name\":\"@truenine/memory-sync-mcp\"",
61+
] {
62+
assert!(
63+
initialize.stdout.contains(expected),
64+
"initialize output should include `{expected}`.\nstdout:\n{}",
65+
initialize.stdout
66+
);
67+
}
68+
69+
container.exec_success(
70+
r#"
71+
MAIN_PACKAGE_JSON="$(find -L /pnpm/global -path '*/@truenine/memory-sync-mcp/package.json' -print -quit)"
72+
PLATFORM_PACKAGE_JSON="$(find -L /pnpm/global -path '*/@truenine/memory-sync-mcp-linux-x64-gnu/package.json' -print -quit)"
73+
test -n "$MAIN_PACKAGE_JSON"
74+
test -n "$PLATFORM_PACKAGE_JSON"
75+
test -f "$(dirname "$MAIN_PACKAGE_JSON")/bin/tnmsm.js"
76+
test -x "$(dirname "$PLATFORM_PACKAGE_JSON")/bin/tnmsm"
77+
test -x "$(command -v tnmsm)"
78+
"#,
79+
);
80+
}

mcp/src/main.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,14 @@ fn main() -> ExitCode {
394394

395395
match resolve_command(&cli) {
396396
ResolvedCommand::Serve => {
397-
// Fixes #225: in stdio mode stdout is the MCP JSON-RPC transport, so
398-
// server startup must not emit logger messages or spans there.
397+
let _span = logger.span("server.serve").enter();
398+
logger.info(
399+
"MCP server started",
400+
Some(json!({
401+
"serverName": SERVER_NAME,
402+
"protocolVersion": PROTOCOL_VERSION,
403+
})),
404+
);
399405
run_stdio_server();
400406
ExitCode::SUCCESS
401407
}

sdk/src/domain/output_plans/codex_output_plan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use std::path::PathBuf;
2020
use crate::CliError;
2121
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
2222
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
23+
use crate::domain::config;
2324
use crate::domain::output_context::OutputContext;
24-
use crate::domain::output_plans::shared::resolve_effective_home_dir;
2525
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
2626

2727
const CODEX_PLUGIN_NAME: &str = "CodexCLIOutputAdaptor";

sdk/src/domain/output_plans/droid_output_plan.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ use serde_json::{Map, Value};
66

77
use crate::CliError;
88
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
9+
use crate::domain::config;
910
use crate::domain::output_context::OutputContext;
10-
use crate::domain::output_plans::shared::resolve_effective_home_dir;
1111
use crate::domain::plugin_shared::{
12-
Project, RelativePath, RuleScope, SkillPrompt, SlashCommandPrompt, Workspace,
12+
FastCommandPrompt, Project, RelativePath, RuleScope, SkillPrompt, SkillResourceEncoding,
13+
Workspace,
1314
};
1415

1516
const DROID_PLUGIN_NAME: &str = "DroidCLIOutputAdaptor";

sdk/src/domain/output_plans/gemini_output_plan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::path::PathBuf;
44
use crate::CliError;
55
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
66
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
7+
use crate::domain::config;
78
use crate::domain::output_context::OutputContext;
8-
use crate::domain::output_plans::shared::resolve_effective_home_dir;
99
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
1010

1111
const GEMINI_PLUGIN_NAME: &str = "GeminiCLIOutputAdaptor";

sdk/src/domain/output_plans/opencode_output_plan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use serde_json::Value;
55
use crate::CliError;
66
use crate::domain::base_output_plans::{BaseOutputFileDeclarationDto, BaseOutputPluginPlanDto};
77
use crate::domain::cleanup::{CleanupDeclarationsDto, CleanupTargetDto, CleanupTargetKindDto};
8+
use crate::domain::config;
89
use crate::domain::output_context::OutputContext;
9-
use crate::domain::output_plans::shared::resolve_effective_home_dir;
1010
use crate::domain::plugin_shared::{Project, RelativePath, Workspace};
1111

1212
const OPENCODE_PLUGIN_NAME: &str = "OpencodeCLIOutputAdaptor";

sdk/src/infra/logger/sink.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::io::{self, Write};
2-
use std::sync::mpsc::{self, Receiver, SendError, Sender};
2+
use std::sync::mpsc::{self, Receiver, Sender};
33
use std::sync::{LazyLock, Mutex};
44
use std::thread;
55

@@ -76,7 +76,7 @@ pub fn flush() {
7676
.send(OutputCommand::Flush { ack: ack_tx })
7777
.is_ok()
7878
{
79-
let _ = ack_rx.recv_timeout(FLUSH_TIMEOUT);
79+
let _ = ack_rx.recv();
8080
}
8181
}
8282

@@ -85,12 +85,12 @@ pub fn flush() {
8585
// ---------------------------------------------------------------------------
8686

8787
fn send_output(use_stderr: bool, output: String) {
88-
// Move the formatted string straight into the channel. On the rare
89-
// sink-thread-dead path the channel hands it back via the SendError
90-
// payload, so the fallback `write_direct` can borrow it without us
91-
// paying a per-call `String::clone` on every log line (#189).
92-
if let Err(SendError(OutputCommand::Write { output, .. })) =
93-
OUTPUT_SINK.send(OutputCommand::Write { use_stderr, output })
88+
if OUTPUT_SINK
89+
.send(OutputCommand::Write {
90+
use_stderr,
91+
output: output.clone(),
92+
})
93+
.is_err()
9494
{
9595
write_direct(use_stderr, &output);
9696
}

sdk/src/services/clean_service.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub fn clean(options: MemorySyncCommandOptions) -> Result<MemorySyncCommandResul
2424
options
2525
.log_level
2626
.as_deref()
27-
.and_then(crate::infra::logger::LogLevel::from_str_loose),
27+
.and_then(|s| crate::infra::logger::LogLevel::from_str_loose(s)),
2828
);
2929
let _span = logger.span("command.clean").enter();
3030

@@ -149,7 +149,7 @@ pub fn clean(options: MemorySyncCommandOptions) -> Result<MemorySyncCommandResul
149149
} else {
150150
let execute_span = logger.span("cleanup.execute").enter();
151151
let result =
152-
crate::policy::cleanup::perform_cleanup(snapshot).map_err(CliError::ExecutionError)?;
152+
crate::policy::cleanup::perform_cleanup(snapshot).map_err(|e| CliError::ExecutionError(e))?;
153153
execute_span.exit();
154154

155155
let blocked = !result.violations.is_empty() || !result.conflicts.is_empty();
@@ -317,7 +317,7 @@ fn build_output_map(
317317
{
318318
cleanup_map
319319
.entry("ClaudeCodeCLIOutputAdaptor".to_string())
320-
.or_default()
320+
.or_insert_with(CleanupDeclarationsDto::default)
321321
.delete
322322
.extend(plan.cleanup.delete.clone());
323323
if enabled_plugins.claude_code {
@@ -333,7 +333,7 @@ fn build_output_map(
333333
{
334334
cleanup_map
335335
.entry("CodexCLIOutputAdaptor".to_string())
336-
.or_default()
336+
.or_insert_with(CleanupDeclarationsDto::default)
337337
.delete
338338
.extend(plan.cleanup.delete.clone());
339339
if enabled_plugins.codex {
@@ -350,7 +350,7 @@ fn build_output_map(
350350
{
351351
cleanup_map
352352
.entry("CursorOutputAdaptor".to_string())
353-
.or_default()
353+
.or_insert_with(CleanupDeclarationsDto::default)
354354
.delete
355355
.extend(plan.cleanup.delete.clone());
356356
if enabled_plugins.cursor {
@@ -366,7 +366,7 @@ fn build_output_map(
366366
{
367367
cleanup_map
368368
.entry("DroidCLIOutputAdaptor".to_string())
369-
.or_default()
369+
.or_insert_with(CleanupDeclarationsDto::default)
370370
.delete
371371
.extend(plan.cleanup.delete.clone());
372372
if enabled_plugins.droid {
@@ -383,7 +383,7 @@ fn build_output_map(
383383
{
384384
cleanup_map
385385
.entry("GeminiCLIOutputAdaptor".to_string())
386-
.or_default()
386+
.or_insert_with(CleanupDeclarationsDto::default)
387387
.delete
388388
.extend(plan.cleanup.delete.clone());
389389
if enabled_plugins.gemini {
@@ -404,7 +404,7 @@ fn build_output_map(
404404
if let Ok(plan) = crate::domain::output_plans::kiro_output_plan::build_kiro_output_plan(context) {
405405
cleanup_map
406406
.entry("KiroCLIOutputAdaptor".to_string())
407-
.or_default()
407+
.or_insert_with(CleanupDeclarationsDto::default)
408408
.delete
409409
.extend(plan.cleanup.delete.clone());
410410
if enabled_plugins.kiro {
@@ -421,7 +421,7 @@ fn build_output_map(
421421
{
422422
cleanup_map
423423
.entry("OpencodeCLIOutputAdaptor".to_string())
424-
.or_default()
424+
.or_insert_with(CleanupDeclarationsDto::default)
425425
.delete
426426
.extend(plan.cleanup.delete.clone());
427427
if enabled_plugins.opencode {
@@ -437,7 +437,7 @@ fn build_output_map(
437437
{
438438
cleanup_map
439439
.entry("QoderIDEPluginOutputAdaptor".to_string())
440-
.or_default()
440+
.or_insert_with(CleanupDeclarationsDto::default)
441441
.delete
442442
.extend(plan.cleanup.delete.clone());
443443
if enabled_plugins.qoder {
@@ -452,7 +452,7 @@ fn build_output_map(
452452
if let Ok(plan) = crate::domain::output_plans::trae_output_plan::build_trae_output_plan(context) {
453453
cleanup_map
454454
.entry("TraeOutputAdaptor".to_string())
455-
.or_default()
455+
.or_insert_with(CleanupDeclarationsDto::default)
456456
.delete
457457
.extend(plan.cleanup.delete.clone());
458458
if enabled_plugins.trae || enabled_plugins.trae_cn {
@@ -467,7 +467,7 @@ fn build_output_map(
467467
if let Ok(plan) = crate::domain::output_plans::warp_output_plan::build_warp_output_plan(context) {
468468
cleanup_map
469469
.entry("WarpIDEOutputAdaptor".to_string())
470-
.or_default()
470+
.or_insert_with(CleanupDeclarationsDto::default)
471471
.delete
472472
.extend(plan.cleanup.delete.clone());
473473
if enabled_plugins.warp {
@@ -484,7 +484,7 @@ fn build_output_map(
484484
{
485485
cleanup_map
486486
.entry("WindsurfOutputAdaptor".to_string())
487-
.or_default()
487+
.or_insert_with(CleanupDeclarationsDto::default)
488488
.delete
489489
.extend(plan.cleanup.delete.clone());
490490
if enabled_plugins.windsurf {

sdk/src/services/dry_run_service.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub fn dry_run(options: MemorySyncCommandOptions) -> Result<MemorySyncCommandRes
2727
options
2828
.log_level
2929
.as_deref()
30-
.and_then(crate::infra::logger::LogLevel::from_str_loose),
30+
.and_then(|s| crate::infra::logger::LogLevel::from_str_loose(s)),
3131
);
3232
let _span = logger.span("command.dry_run").enter();
3333

@@ -79,7 +79,7 @@ pub fn dry_run(options: MemorySyncCommandOptions) -> Result<MemorySyncCommandRes
7979
"Context collected",
8080
Some(json!({
8181
"globalMemory": context.global_memory.is_some(),
82-
"commands": context.slash_commands.as_ref().map(|v| v.len()),
82+
"commands": context.fast_commands.as_ref().map(|v| v.len()),
8383
"skills": context.skills.as_ref().map(|v| v.len()),
8484
"rules": context.rules.as_ref().map(|v| v.len()),
8585
})),

sdk/src/services/install_service.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub(crate) fn install(
3333
options
3434
.log_level
3535
.as_deref()
36-
.and_then(crate::infra::logger::LogLevel::from_str_loose),
36+
.and_then(|s| crate::infra::logger::LogLevel::from_str_loose(s)),
3737
);
3838
let _span = logger.span("command.install").enter();
3939

@@ -91,7 +91,7 @@ pub(crate) fn install(
9191
"Context collected",
9292
Some(json!({
9393
"globalMemory": context.global_memory.is_some(),
94-
"commands": context.slash_commands.as_ref().map(|v| v.len()),
94+
"commands": context.fast_commands.as_ref().map(|v| v.len()),
9595
"skills": context.skills.as_ref().map(|v| v.len()),
9696
"rules": context.rules.as_ref().map(|v| v.len()),
9797
})),

0 commit comments

Comments
 (0)