swarm repositories / source
aboutsummaryrefslogtreecommitdiff
path: root/crates/jira-at-home
diff options
context:
space:
mode:
Diffstat (limited to 'crates/jira-at-home')
-rw-r--r--crates/jira-at-home/src/mcp/catalog.rs4
-rw-r--r--crates/jira-at-home/src/mcp/host/runtime.rs2
-rw-r--r--crates/jira-at-home/src/mcp/service.rs26
-rw-r--r--crates/jira-at-home/src/store.rs4
-rw-r--r--crates/jira-at-home/tests/mcp_hardening.rs5
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);