Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mempalace/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from pathlib import Path

from .config import MempalaceConfig
from .version import __version__


def cmd_init(args):
Expand Down Expand Up @@ -399,6 +400,9 @@ def main():
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument(
"--version", action="version", version=f"mempalace {__version__}"
)
parser.add_argument(
"--palace",
default=None,
Expand Down
6 changes: 5 additions & 1 deletion mempalace/instructions/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ before continuing.

## Step 5: Initialize the palace

Run `mempalace init <dir>` where `<dir>` is the directory from Step 4.
Run `mempalace init --yes <dir>` where `<dir>` is the directory from Step 4.

The `--yes` flag is required in agent/non-interactive contexts to auto-accept
detected entities and rooms without prompting. Without it, the command will
crash with EOFError when stdin is not a terminal.

If this fails, report the error and stop.

Expand Down
12 changes: 12 additions & 0 deletions mempalace/instructions/mine.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

When the user invokes this skill, follow these steps:

## 0. Ensure the palace is initialized

Before mining, the target directory must be initialized with `mempalace init --yes <dir>`.
Check if a `mempalace.yaml` file exists in the target directory. If not, run init first:

```bash
mempalace init --yes <dir>
```

Without this, `mempalace mine` will fail with:
`ERROR: No mempalace.yaml found in <dir>`

## 1. Ask what to mine

Ask the user what they want to mine and where the source data is located.
Expand Down
30 changes: 30 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,29 @@ def test_cmd_init_with_entities_zero_total(mock_config_cls, tmp_path, capsys):
assert "No entities detected" in out


@patch("mempalace.cli.MempalaceConfig")
def test_cmd_init_yes_skips_interactive_prompts(mock_config_cls, tmp_path):
"""init --yes must not call input(), so agents don't hit EOFError."""
fake_files = [tmp_path / "a.txt"]
detected = {
"people": [{"name": "Alice", "confidence": 0.9, "signals": ["dialogue"]}],
"projects": [],
"uncertain": [{"name": "Bob", "frequency": 5, "signals": ["appears 5x"]}],
}
confirmed = {"people": ["Alice"], "projects": []}
args = argparse.Namespace(dir=str(tmp_path), yes=True)
with (
patch("mempalace.entity_detector.scan_for_detection", return_value=fake_files),
patch("mempalace.entity_detector.detect_entities", return_value=detected),
patch("mempalace.entity_detector.confirm_entities", return_value=confirmed) as mock_confirm,
patch("mempalace.room_detector_local.detect_rooms_local"),
patch("builtins.open", MagicMock()),
):
cmd_init(args)
# Verify yes=True was passed through to confirm_entities
mock_confirm.assert_called_once_with(detected, yes=True)


# ── cmd_mine ───────────────────────────────────────────────────────────


Expand Down Expand Up @@ -266,6 +289,13 @@ def test_cmd_split_all_options():
# ── main() argparse dispatch ──────────────────────────────────────────


def test_main_version_flag(capsys):
with patch("sys.argv", ["mempalace", "--version"]), pytest.raises(SystemExit, match="0"):
main()
out = capsys.readouterr().out
assert "mempalace" in out


def test_main_no_args_prints_help(capsys):
with patch("sys.argv", ["mempalace"]):
main()
Expand Down
14 changes: 14 additions & 0 deletions tests/test_instructions_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,17 @@ def test_run_instructions_missing_md_file(capsys, tmp_path):
assert exc_info.value.code == 1
captured = capsys.readouterr()
assert "Instructions file not found" in captured.err


def test_init_instructions_use_yes_flag():
"""init instructions must tell agents to use --yes to avoid EOFError."""
content = (INSTRUCTIONS_DIR / "init.md").read_text()
assert "--yes" in content
assert "mempalace init --yes" in content


def test_mine_instructions_mention_init_prerequisite():
"""mine instructions must mention that init --yes is required first."""
content = (INSTRUCTIONS_DIR / "mine.md").read_text()
assert "mempalace init --yes" in content
assert "mempalace.yaml" in content