swarph-cli 0.9.3__tar.gz → 0.9.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swarph_cli-0.9.3/src/swarph_cli.egg-info → swarph_cli-0.9.4}/PKG-INFO +2 -2
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/pyproject.toml +2 -2
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/cell.py +60 -8
- {swarph_cli-0.9.3 → swarph_cli-0.9.4/src/swarph_cli.egg-info}/PKG-INFO +2 -2
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_cell_loader.py +103 -4
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_spawn_command.py +3 -3
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/LICENSE +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/README.md +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/setup.cfg +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli.egg-info/SOURCES.txt +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_import_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_init_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_main.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.9.3 → swarph_cli-0.9.4}/tests/test_watchdog.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.9.
|
|
4
|
-
Summary: The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider spawn (claude/codex/antigravity per cell.provider via a ProviderMembrane), `swarph init
|
|
3
|
+
Version: 0.9.4
|
|
4
|
+
Summary: The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider `swarph spawn` (claude/codex/antigravity per cell.provider via a ProviderMembrane + subprocess billing-scrub), interactive `swarph init`, `swarph mesh` (send/inbox/register) + inbox sidecar, `assisted_memory` (git-backed durable memory), session import, watchdog. v0.9.4: fixes session-pin resume across a changed cwd.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/darw007d/swarph-cli
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.9.
|
|
8
|
-
description = "The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider spawn (claude/codex/antigravity per cell.provider via a ProviderMembrane), `swarph init
|
|
7
|
+
version = "0.9.4"
|
|
8
|
+
description = "The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider `swarph spawn` (claude/codex/antigravity per cell.provider via a ProviderMembrane + subprocess billing-scrub), interactive `swarph init`, `swarph mesh` (send/inbox/register) + inbox sidecar, `assisted_memory` (git-backed durable memory), session import, watchdog. v0.9.4: fixes session-pin resume across a changed cwd."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -252,6 +252,42 @@ def load_cell(path: Path) -> Cell:
|
|
|
252
252
|
return cell
|
|
253
253
|
|
|
254
254
|
|
|
255
|
+
def _write_session_sidecar(target: Path, session_id: str, cwd) -> None:
|
|
256
|
+
"""Write the two-line ``{uuid, cwd}`` session sidecar atomically.
|
|
257
|
+
|
|
258
|
+
v0.9.4 (session-pin cwd-mismatch fix): the sidecar records the cwd
|
|
259
|
+
the session UUID was minted for so a later spawn from a DIFFERENT
|
|
260
|
+
cwd can detect the mismatch and re-pin a fresh UUID rather than
|
|
261
|
+
handing a project-scoped UUID to ``claude --resume`` from the wrong
|
|
262
|
+
project (which dies with "No conversation found with session ID").
|
|
263
|
+
|
|
264
|
+
Format (trailing-newline convention preserved):
|
|
265
|
+
|
|
266
|
+
<uuid>\\n
|
|
267
|
+
<cwd>\\n
|
|
268
|
+
"""
|
|
269
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
270
|
+
_atomic_write_text(target, f"{session_id}\n{str(cwd)}\n")
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _read_session_sidecar(path: Path) -> tuple[Optional[str], Optional[str]]:
|
|
274
|
+
"""Parse a session sidecar → ``(uuid, cwd)``.
|
|
275
|
+
|
|
276
|
+
Returns ``(None, None)`` for a missing/empty file. ``cwd`` is
|
|
277
|
+
``None`` for a **legacy one-line** sidecar (bare UUID, pre-0.9.4)
|
|
278
|
+
— we cannot know which project that UUID belongs to.
|
|
279
|
+
"""
|
|
280
|
+
if not path.exists():
|
|
281
|
+
return None, None
|
|
282
|
+
raw = path.read_text(encoding="utf-8")
|
|
283
|
+
lines = raw.splitlines()
|
|
284
|
+
if not lines:
|
|
285
|
+
return None, None
|
|
286
|
+
uuid_str = lines[0].strip() or None
|
|
287
|
+
cwd_str = lines[1].strip() if len(lines) >= 2 and lines[1].strip() else None
|
|
288
|
+
return uuid_str, cwd_str
|
|
289
|
+
|
|
290
|
+
|
|
255
291
|
def load_or_create_session_id(
|
|
256
292
|
role: str,
|
|
257
293
|
cell: Cell,
|
|
@@ -266,6 +302,10 @@ def load_or_create_session_id(
|
|
|
266
302
|
2. ``new_instance=True`` AND base sidecar exists — auto-suffix slot
|
|
267
303
|
3. ``new_instance=True`` AND no base sidecar — fall through (degenerate)
|
|
268
304
|
4. session_state_path(role) reused — default re-resume path
|
|
305
|
+
(v0.9.4: only when the sidecar's recorded cwd matches cell.cwd;
|
|
306
|
+
on cwd-mismatch a fresh UUID is minted + re-pinned for the new
|
|
307
|
+
cwd, because ``claude --resume`` is PROJECT-scoped and a pin
|
|
308
|
+
from another cwd dies with "No conversation found")
|
|
269
309
|
5. mint new uuid4 + persist
|
|
270
310
|
|
|
271
311
|
Caller-side discipline (mother iter-1 #986): the ``effective_role``
|
|
@@ -282,23 +322,33 @@ def load_or_create_session_id(
|
|
|
282
322
|
sibling_role = next_free_slot_role(role)
|
|
283
323
|
sibling_state = session_state_path(sibling_role)
|
|
284
324
|
new_id = str(uuid.uuid4())
|
|
285
|
-
sibling_state
|
|
286
|
-
_atomic_write_text(sibling_state, new_id + "\n")
|
|
325
|
+
_write_session_sidecar(sibling_state, new_id, cell.cwd)
|
|
287
326
|
return new_id, True, sibling_role
|
|
288
327
|
|
|
289
328
|
state_file = session_state_path(role)
|
|
290
329
|
if state_file.exists():
|
|
291
|
-
|
|
292
|
-
if
|
|
330
|
+
existing_uuid, recorded_cwd = _read_session_sidecar(state_file)
|
|
331
|
+
if existing_uuid:
|
|
293
332
|
try:
|
|
294
|
-
|
|
333
|
+
valid_uuid = validate_uuid_str(existing_uuid)
|
|
295
334
|
except CellError:
|
|
296
335
|
# Corrupted state — fall through and regenerate.
|
|
297
|
-
|
|
336
|
+
valid_uuid = None
|
|
337
|
+
if valid_uuid is not None:
|
|
338
|
+
if recorded_cwd is not None and recorded_cwd != str(cell.cwd):
|
|
339
|
+
# v0.9.4: pin belongs to a different project. A
|
|
340
|
+
# project-scoped --resume would die from this cwd, so
|
|
341
|
+
# mint a fresh (clean) UUID + re-pin for the new cwd.
|
|
342
|
+
fresh = str(uuid.uuid4())
|
|
343
|
+
_write_session_sidecar(state_file, fresh, cell.cwd)
|
|
344
|
+
return fresh, True, role
|
|
345
|
+
# Legacy (recorded_cwd is None) → reuse as-is; do NOT
|
|
346
|
+
# rewrite, since the UUID's true origin cwd is unknown.
|
|
347
|
+
# Matching cwd → reuse.
|
|
348
|
+
return valid_uuid, False, role
|
|
298
349
|
|
|
299
350
|
new_id = str(uuid.uuid4())
|
|
300
|
-
state_file
|
|
301
|
-
_atomic_write_text(state_file, new_id + "\n")
|
|
351
|
+
_write_session_sidecar(state_file, new_id, cell.cwd)
|
|
302
352
|
return new_id, True, role
|
|
303
353
|
|
|
304
354
|
|
|
@@ -352,6 +402,8 @@ __all__ = [
|
|
|
352
402
|
"read_starter_prompt",
|
|
353
403
|
"load_cell",
|
|
354
404
|
"load_or_create_session_id",
|
|
405
|
+
"_read_session_sidecar",
|
|
406
|
+
"_write_session_sidecar",
|
|
355
407
|
# Backward-compat aliases
|
|
356
408
|
"_PEER_NAME_RE",
|
|
357
409
|
"_VALID_SCHEMA_VERSIONS",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.9.
|
|
4
|
-
Summary: The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider spawn (claude/codex/antigravity per cell.provider via a ProviderMembrane), `swarph init
|
|
3
|
+
Version: 0.9.4
|
|
4
|
+
Summary: The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider `swarph spawn` (claude/codex/antigravity per cell.provider via a ProviderMembrane + subprocess billing-scrub), interactive `swarph init`, `swarph mesh` (send/inbox/register) + inbox sidecar, `assisted_memory` (git-backed durable memory), session import, watchdog. v0.9.4: fixes session-pin resume across a changed cwd.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/darw007d/swarph-cli
|
|
@@ -22,6 +22,8 @@ from swarph_cli.cell import (
|
|
|
22
22
|
load_or_create_session_id,
|
|
23
23
|
resolve_cell_path,
|
|
24
24
|
session_state_path,
|
|
25
|
+
_read_session_sidecar,
|
|
26
|
+
_write_session_sidecar,
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
|
|
@@ -264,7 +266,9 @@ def test_load_or_create_session_id_mints_and_persists(
|
|
|
264
266
|
uuid.UUID(sid1) # raises if not a valid UUID
|
|
265
267
|
sidecar = session_state_path("lab")
|
|
266
268
|
assert sidecar.exists()
|
|
267
|
-
|
|
269
|
+
rec_uuid, rec_cwd = _read_session_sidecar(sidecar)
|
|
270
|
+
assert rec_uuid == sid1
|
|
271
|
+
assert rec_cwd == str(cell.cwd)
|
|
268
272
|
|
|
269
273
|
|
|
270
274
|
def test_load_or_create_session_id_reuses_persisted_value(
|
|
@@ -287,7 +291,102 @@ def test_load_or_create_session_id_corrupted_sidecar_regenerates(
|
|
|
287
291
|
sid, generated, _role = load_or_create_session_id("lab", cell)
|
|
288
292
|
uuid.UUID(sid)
|
|
289
293
|
assert generated is True
|
|
290
|
-
|
|
294
|
+
rec_uuid, _rec_cwd = _read_session_sidecar(sidecar)
|
|
295
|
+
assert rec_uuid == sid
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# ---------------------------------------------------------------------------
|
|
299
|
+
# v0.9.4 — session-pin cwd-mismatch fix (project-scoped --resume)
|
|
300
|
+
# ---------------------------------------------------------------------------
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def test_session_sidecar_fresh_mint_writes_two_line_uuid_and_cwd(
|
|
304
|
+
isolated_xdg, cell_yaml_factory, tmp_path
|
|
305
|
+
):
|
|
306
|
+
"""v0.9.4 — first mint records BOTH the uuid AND the cwd (cwd=A)."""
|
|
307
|
+
cell = load_cell(cell_yaml_factory()) # cwd == tmp_path (== A)
|
|
308
|
+
sid, gen, _role = load_or_create_session_id("lab", cell)
|
|
309
|
+
assert gen is True
|
|
310
|
+
uuid.UUID(sid)
|
|
311
|
+
rec_uuid, rec_cwd = _read_session_sidecar(session_state_path("lab"))
|
|
312
|
+
assert rec_uuid == sid
|
|
313
|
+
assert rec_cwd == str(tmp_path)
|
|
314
|
+
assert rec_cwd == str(cell.cwd)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def test_session_sidecar_same_cwd_reuses_same_uuid(
|
|
318
|
+
isolated_xdg, cell_yaml_factory, tmp_path
|
|
319
|
+
):
|
|
320
|
+
"""v0.9.4 — pre-pinned {uuid=U, cwd=A}; spawn from cwd=A reuses U."""
|
|
321
|
+
cell = load_cell(cell_yaml_factory()) # cwd == tmp_path (== A)
|
|
322
|
+
fixed = "550e8400-e29b-41d4-a716-446655440000"
|
|
323
|
+
_write_session_sidecar(session_state_path("lab"), fixed, str(tmp_path))
|
|
324
|
+
sid, gen, role = load_or_create_session_id("lab", cell)
|
|
325
|
+
assert sid == fixed
|
|
326
|
+
assert gen is False
|
|
327
|
+
assert role == "lab"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def test_session_sidecar_different_cwd_mints_fresh_and_repins(
|
|
331
|
+
isolated_xdg, cell_yaml_factory, tmp_path
|
|
332
|
+
):
|
|
333
|
+
"""v0.9.4 REGRESSION — the bug: pin minted for cwd=A, spawn from cwd=B.
|
|
334
|
+
|
|
335
|
+
A project-scoped ``claude --resume <U>`` from B dies with
|
|
336
|
+
"No conversation found". Fix: mint a FRESH (clean) uuid and re-pin
|
|
337
|
+
it for cwd=B.
|
|
338
|
+
"""
|
|
339
|
+
cwd_b = tmp_path / "project_b"
|
|
340
|
+
cwd_b.mkdir()
|
|
341
|
+
cell = load_cell(cell_yaml_factory(cwd=str(cwd_b))) # cell.cwd == B
|
|
342
|
+
fixed = "550e8400-e29b-41d4-a716-446655440000" # pinned for cwd=A
|
|
343
|
+
_write_session_sidecar(session_state_path("lab"), fixed, str(tmp_path))
|
|
344
|
+
|
|
345
|
+
sid, gen, role = load_or_create_session_id("lab", cell)
|
|
346
|
+
assert gen is True
|
|
347
|
+
assert sid != fixed # genuine fresh UUID
|
|
348
|
+
uuid.UUID(sid)
|
|
349
|
+
assert role == "lab"
|
|
350
|
+
# Sidecar now re-pinned for cwd=B with the fresh UUID.
|
|
351
|
+
rec_uuid, rec_cwd = _read_session_sidecar(session_state_path("lab"))
|
|
352
|
+
assert rec_uuid == sid
|
|
353
|
+
assert rec_cwd == str(cwd_b)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def test_session_sidecar_legacy_one_line_is_reused_not_reminted(
|
|
357
|
+
isolated_xdg, cell_yaml_factory, tmp_path
|
|
358
|
+
):
|
|
359
|
+
"""v0.9.4 back-compat — legacy bare-uuid (no cwd) sidecar is reused
|
|
360
|
+
as-is regardless of cwd (origin cwd unknown; do NOT re-mint)."""
|
|
361
|
+
cell = load_cell(cell_yaml_factory())
|
|
362
|
+
fixed = "550e8400-e29b-41d4-a716-446655440000"
|
|
363
|
+
sidecar = session_state_path("lab")
|
|
364
|
+
sidecar.parent.mkdir(parents=True, exist_ok=True)
|
|
365
|
+
sidecar.write_text(fixed + "\n") # legacy one-line format
|
|
366
|
+
sid, gen, role = load_or_create_session_id("lab", cell)
|
|
367
|
+
assert sid == fixed
|
|
368
|
+
assert gen is False
|
|
369
|
+
assert role == "lab"
|
|
370
|
+
# Not upgraded/rewritten — stays legacy one-line.
|
|
371
|
+
assert sidecar.read_text() == fixed + "\n"
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def test_read_session_sidecar_parses_both_formats(tmp_path):
|
|
375
|
+
"""v0.9.4 — _read_session_sidecar handles 2-line AND legacy 1-line."""
|
|
376
|
+
two_line = tmp_path / "two.session-id"
|
|
377
|
+
two_line.write_text("550e8400-e29b-41d4-a716-446655440000\n/home/x/proj\n")
|
|
378
|
+
assert _read_session_sidecar(two_line) == (
|
|
379
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
380
|
+
"/home/x/proj",
|
|
381
|
+
)
|
|
382
|
+
one_line = tmp_path / "one.session-id"
|
|
383
|
+
one_line.write_text("550e8400-e29b-41d4-a716-446655440000\n")
|
|
384
|
+
assert _read_session_sidecar(one_line) == (
|
|
385
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
386
|
+
None,
|
|
387
|
+
)
|
|
388
|
+
missing = tmp_path / "missing.session-id"
|
|
389
|
+
assert _read_session_sidecar(missing) == (None, None)
|
|
291
390
|
|
|
292
391
|
|
|
293
392
|
def test_load_or_create_session_id_atomic_no_tempfile_left_behind(
|
|
@@ -435,8 +534,8 @@ def test_new_instance_with_existing_base_mints_into_slot_2(
|
|
|
435
534
|
base_path = session_state_path("drop")
|
|
436
535
|
sib_path = session_state_path("drop-2")
|
|
437
536
|
assert base_path.exists() and sib_path.exists()
|
|
438
|
-
assert base_path
|
|
439
|
-
assert sib_path
|
|
537
|
+
assert _read_session_sidecar(base_path)[0] == sid_base
|
|
538
|
+
assert _read_session_sidecar(sib_path)[0] == sid_sib
|
|
440
539
|
|
|
441
540
|
|
|
442
541
|
def test_new_instance_third_call_lands_at_slot_3(
|
|
@@ -459,7 +459,7 @@ def test_run_spawn_new_instance_with_base_mints_sibling_slot(
|
|
|
459
459
|
):
|
|
460
460
|
"""v0.7 PR-B — `--new-instance` with base sidecar present allocates
|
|
461
461
|
slot 2 AND persists. Sibling resumable via `swarph spawn <role>-2`."""
|
|
462
|
-
from swarph_cli.cell import session_state_path
|
|
462
|
+
from swarph_cli.cell import session_state_path, _read_session_sidecar
|
|
463
463
|
|
|
464
464
|
# First spawn establishes base slot
|
|
465
465
|
run_spawn(argv=[str(fake_cell_yaml), "--dry-run", "--print-id"])
|
|
@@ -474,8 +474,8 @@ def test_run_spawn_new_instance_with_base_mints_sibling_slot(
|
|
|
474
474
|
|
|
475
475
|
base_sidecar = session_state_path("lab-test")
|
|
476
476
|
sibling_sidecar = session_state_path("lab-test-2")
|
|
477
|
-
assert base_sidecar
|
|
478
|
-
assert sibling_sidecar
|
|
477
|
+
assert _read_session_sidecar(base_sidecar)[0] == base_uuid
|
|
478
|
+
assert _read_session_sidecar(sibling_sidecar)[0] == sibling_uuid
|
|
479
479
|
|
|
480
480
|
# Dry-run output shows the sibling slot label
|
|
481
481
|
assert "lab-test-2" in captured.err
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|