diff options
Diffstat (limited to 'crates/jira-at-home')
| -rw-r--r-- | crates/jira-at-home/src/mcp/catalog.rs | 4 | ||||
| -rw-r--r-- | crates/jira-at-home/src/mcp/host/runtime.rs | 2 | ||||
| -rw-r--r-- | crates/jira-at-home/src/mcp/service.rs | 26 | ||||
| -rw-r--r-- | crates/jira-at-home/src/store.rs | 4 | ||||
| -rw-r--r-- | crates/jira-at-home/tests/mcp_hardening.rs | 5 |
5 files changed, 20 insertions, 21 deletions
diff --git a/crates/jira-at-home/src/mcp/catalog.rs b/crates/jira-at-home/src/mcp/catalog.rs index 2ff8e81..d6ce29b 100644 --- a/crates/jira-at-home/src/mcp/catalog.rs +++ b/crates/jira-at-home/src/mcp/catalog.rs @@ -47,7 +47,7 @@ const TOOL_SPECS: &[ToolSpec] = &[ }, ToolSpec { name: "issue.save", - description: "Create or overwrite one issue note at `issues/<slug>.md`.", + description: "Create or overwrite one issue note at `issues/<slug>.md` under the bound project's external state root.", dispatch: DispatchTarget::Worker, replay: ReplayContract::NeverReplay, }, @@ -112,7 +112,7 @@ fn tool_schema(name: &str) -> Value { "properties": { "slug": { "type": "string", - "description": "Stable slug. Stored at `issues/<slug>.md`." + "description": "Stable slug. Stored at `issues/<slug>.md` under the bound project's external state root." }, "body": { "type": "string", diff --git a/crates/jira-at-home/src/mcp/host/runtime.rs b/crates/jira-at-home/src/mcp/host/runtime.rs index b2049a0..1994632 100644 --- a/crates/jira-at-home/src/mcp/host/runtime.rs +++ b/crates/jira-at-home/src/mcp/host/runtime.rs @@ -230,7 +230,7 @@ impl HostRuntime { "name": SERVER_NAME, "version": env!("CARGO_PKG_VERSION") }, - "instructions": "Bind the session with project.bind, then use issue.save to park ideas in issues/<slug>.md. issue.list enumerates every existing issue file because there is no closed state." + "instructions": "Bind the session with project.bind, then use issue.save to park ideas in the bound state directory under issues/<slug>.md. issue.list enumerates every existing issue file because there is no closed state." }))), "notifications/initialized" => { if !self.seed_captured() { diff --git a/crates/jira-at-home/src/mcp/service.rs b/crates/jira-at-home/src/mcp/service.rs index fc9dbf0..2a98829 100644 --- a/crates/jira-at-home/src/mcp/service.rs +++ b/crates/jira-at-home/src/mcp/service.rs @@ -84,7 +84,7 @@ impl WorkerService { .map_err(store_fault(self.generation, &operation))?; issue_save_output( &receipt, - self.store.layout().project_root.as_path(), + self.store.layout().state_root.as_path(), self.generation, &operation, )? @@ -96,7 +96,7 @@ impl WorkerService { .map_err(store_fault(self.generation, &operation))?; issue_list_output( &issues, - self.store.layout().project_root.as_path(), + self.store.layout().state_root.as_path(), self.generation, &operation, )? @@ -111,7 +111,7 @@ impl WorkerService { .map_err(store_fault(self.generation, &operation))?; issue_read_output( &record, - self.store.layout().project_root.as_path(), + self.store.layout().state_root.as_path(), self.generation, &operation, )? @@ -189,11 +189,11 @@ fn store_fault( fn issue_save_output( receipt: &SaveReceipt, - project_root: &Path, + state_root: &Path, generation: Generation, operation: &str, ) -> Result<ToolOutput, FaultRecord> { - let relative_path = relative_issue_path(&receipt.path, project_root); + let relative_path = relative_issue_path(&receipt.path, state_root); let status = if receipt.created { "created" } else { @@ -218,7 +218,7 @@ fn issue_save_output( [ format!("saved issue {}", receipt.slug), format!("status: {status}"), - format!("path: {}", relative_issue_path(&receipt.path, project_root)), + format!("path: {}", relative_issue_path(&receipt.path, state_root)), format!("updated: {}", format_timestamp(receipt.updated_at)), ] .join("\n"), @@ -232,7 +232,7 @@ fn issue_save_output( fn issue_list_output( issues: &[crate::store::IssueSummary], - project_root: &Path, + state_root: &Path, generation: Generation, operation: &str, ) -> Result<ToolOutput, FaultRecord> { @@ -249,10 +249,8 @@ fn issue_list_output( .iter() .map(|issue| { let path = relative_issue_path( - &project_root - .join("issues") - .join(format!("{}.md", issue.slug)), - project_root, + &state_root.join("issues").join(format!("{}.md", issue.slug)), + state_root, ); json!({ "slug": issue.slug, @@ -277,11 +275,11 @@ fn issue_list_output( fn issue_read_output( record: &IssueRecord, - project_root: &Path, + state_root: &Path, generation: Generation, operation: &str, ) -> Result<ToolOutput, FaultRecord> { - let relative_path = relative_issue_path(&record.path, project_root); + let relative_path = relative_issue_path(&record.path, state_root); let concise = json!({ "slug": record.slug, "updated_at": format_timestamp(record.updated_at), @@ -303,7 +301,7 @@ fn issue_read_output( let full_text = Some(format!( "issue {}\npath: {}\nupdated: {}\nbytes: {}\n\n{}", record.slug, - relative_issue_path(&record.path, project_root), + relative_issue_path(&record.path, state_root), format_timestamp(record.updated_at), record.bytes, record.body, diff --git a/crates/jira-at-home/src/store.rs b/crates/jira-at-home/src/store.rs index faf2c9a..238477a 100644 --- a/crates/jira-at-home/src/store.rs +++ b/crates/jira-at-home/src/store.rs @@ -102,9 +102,9 @@ impl ProjectLayout { pub(crate) fn bind(requested_path: impl Into<PathBuf>) -> Result<Self, StoreError> { let requested_path = requested_path.into(); let project_root = resolve_project_root(&requested_path)?; - let issues_root = project_root.join(ISSUES_DIR_NAME); - fs::create_dir_all(&issues_root)?; let state_root = external_state_root(&project_root)?; + let issues_root = state_root.join(ISSUES_DIR_NAME); + fs::create_dir_all(&issues_root)?; fs::create_dir_all(state_root.join("mcp"))?; Ok(Self { requested_path, diff --git a/crates/jira-at-home/tests/mcp_hardening.rs b/crates/jira-at-home/tests/mcp_hardening.rs index 02f4fda..52d9a35 100644 --- a/crates/jira-at-home/tests/mcp_hardening.rs +++ b/crates/jira-at-home/tests/mcp_hardening.rs @@ -231,7 +231,7 @@ fn cold_start_exposes_basic_toolset_and_binding_surface() -> TestResult { } #[test] -fn save_list_and_read_roundtrip_through_canonical_issue_dir() -> TestResult { +fn save_list_and_read_roundtrip_through_state_backed_issue_dir() -> TestResult { let project_root = temp_project_root("roundtrip")?; let state_home = project_root.join("state-home"); must(fs::create_dir_all(&state_home), "create state home")?; @@ -263,11 +263,12 @@ fn save_list_and_read_roundtrip_through_canonical_issue_dir() -> TestResult { Some("issues/feral-machine.md") ); - let saved_path = project_root.join("issues").join("feral-machine.md"); + let saved_path = state_root.join("issues").join("feral-machine.md"); assert_eq!( must(fs::read_to_string(&saved_path), "read saved issue")?, body ); + assert!(!project_root.join("issues").exists()); let list = harness.call_tool(4, "issue.list", json!({}))?; assert_tool_ok(&list); |