swarph-cli 0.10.0__tar.gz → 0.10.2__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.10.0/src/swarph_cli.egg-info → swarph_cli-0.10.2}/PKG-INFO +53 -1
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/README.md +52 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/pyproject.toml +1 -1
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/__init__.py +1 -1
- swarph_cli-0.10.2/src/swarph_cli/commands/compress.py +80 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/init.py +9 -1
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/watchdog.py +383 -37
- swarph_cli-0.10.2/src/swarph_cli/compress/__init__.py +0 -0
- swarph_cli-0.10.2/src/swarph_cli/compress/levers.py +52 -0
- swarph_cli-0.10.2/src/swarph_cli/compress/marker.py +39 -0
- swarph_cli-0.10.2/src/swarph_cli/compress/verify.py +81 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/main.py +1 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2/src/swarph_cli.egg-info}/PKG-INFO +53 -1
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli.egg-info/SOURCES.txt +9 -0
- swarph_cli-0.10.2/tests/test_compress_command.py +33 -0
- swarph_cli-0.10.2/tests/test_compress_levers.py +38 -0
- swarph_cli-0.10.2/tests/test_compress_marker.py +20 -0
- swarph_cli-0.10.2/tests/test_compress_verify.py +62 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_init_command.py +5 -1
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_watchdog.py +36 -4
- swarph_cli-0.10.2/tests/test_watchdog_model_rung.py +881 -0
- swarph_cli-0.10.0/tests/test_watchdog_model_rung.py +0 -465
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/LICENSE +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/setup.cfg +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_import_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_main.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_security.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.10.0 → swarph_cli-0.10.2}/tests/test_watchdog_stale_peers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.2
|
|
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.5: foolproof Windows auto-relaunch (genuine-WT detection via process ancestry, not WT_SESSION).
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -348,6 +348,58 @@ Pong!
|
|
|
348
348
|
# 3+26t $0.0000 0.73s caller=cli.oneshot.ubuntu provider=gemini
|
|
349
349
|
```
|
|
350
350
|
|
|
351
|
+
### `swarph compress` (v0.11 — context-surface compression)
|
|
352
|
+
|
|
353
|
+
Compress a **machine-read context surface** (memory index, manual, agent brief) to
|
|
354
|
+
reclaim always-loaded space/tokens. The principle: fluent natural language carries
|
|
355
|
+
redundancy a model infers for free — *the decompressor is the model itself*. Proven
|
|
356
|
+
by hand on the OMEGA swarm: `MEMORY.md` 37→16KB (58%), `CLAUDE.md` 241→21KB
|
|
357
|
+
always-loaded (91%, archival).
|
|
358
|
+
|
|
359
|
+
**Opt-in by marker (fails safe).** A file is compressible only if it carries an
|
|
360
|
+
explicit marker; unmarked files are left untouched. The model's judgment is spent
|
|
361
|
+
once, in-session, authoring the marker — runtime is pure-Python marker parsing, no
|
|
362
|
+
model in the hot path.
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
<!-- swarph:compress lever=archival boundary="^## Session" -->
|
|
366
|
+
<!-- swarph:compress lever=shorthand pointer="](*.md)" floor=0.45 -->
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Two levers, different risk classes:**
|
|
370
|
+
|
|
371
|
+
| Lever | What | Loss class | Model? |
|
|
372
|
+
|---|---|---|---|
|
|
373
|
+
| `archival` | relocate the cold tail below `boundary` to `<file>.archive.<ext>` + leave a pointer | **lossless** (nothing destroyed) | no — pure Python, zero tokens |
|
|
374
|
+
| `shorthand` | rewrite a pointer-bearing INDEX to telegraphic shorthand | lossy, **bounded to index-over-preserved-source** (recoverable by construction) | yes (`claude -p` subscription path) |
|
|
375
|
+
|
|
376
|
+
Shorthand is gated: redundancy-floor (refuse if already dense), links-superset
|
|
377
|
+
(every `[]()` survives), index-over-source (every entry keeps a resolvable
|
|
378
|
+
pointer), and an **adversarial verify-expand** (an independent model hunts for a
|
|
379
|
+
dropped fact; one found → abort).
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
swarph compress MEMORY.md # dry-run: classify, propose, report savings
|
|
383
|
+
swarph compress MEMORY.md --apply # write (atomic tempfile→mv + .bak + verify-gate)
|
|
384
|
+
swarph compress MEMORY.md --verify-idempotent # assert compress(compress(x)) ≈ noop
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Dry-run is the default — nothing mutates without `--apply`. Cron-friendly exit codes:
|
|
388
|
+
|
|
389
|
+
| Code | Meaning |
|
|
390
|
+
|---|---|
|
|
391
|
+
| `0` | analyzed/savings-reported (or applied clean) |
|
|
392
|
+
| `2` | no such file |
|
|
393
|
+
| `3` | refused — unmarked (leave breathing) |
|
|
394
|
+
| `4` | refused — archival: no boundary line matched |
|
|
395
|
+
| `5` | refused — shorthand: below redundancy floor (already dense) |
|
|
396
|
+
| `6` | refused — shorthand dropped a link / lost a pointer-to-source |
|
|
397
|
+
| `7` | refused — adversarial verify-expand found a dropped fact |
|
|
398
|
+
| `8` | refused — not idempotent (second pass kept cutting; signal-eating alarm) |
|
|
399
|
+
|
|
400
|
+
Design spec: `docs/superpowers/specs/2026-06-11-swarph-context-compressor-design.md`
|
|
401
|
+
(in the hedge-fund-mcp repo).
|
|
402
|
+
|
|
351
403
|
### `--json` mode semantics
|
|
352
404
|
|
|
353
405
|
`--json` is a **harness trigger**, not a strict-validation gate. When set, swarph routes the response through the swarph-mesh JSON harness:
|
|
@@ -313,6 +313,58 @@ Pong!
|
|
|
313
313
|
# 3+26t $0.0000 0.73s caller=cli.oneshot.ubuntu provider=gemini
|
|
314
314
|
```
|
|
315
315
|
|
|
316
|
+
### `swarph compress` (v0.11 — context-surface compression)
|
|
317
|
+
|
|
318
|
+
Compress a **machine-read context surface** (memory index, manual, agent brief) to
|
|
319
|
+
reclaim always-loaded space/tokens. The principle: fluent natural language carries
|
|
320
|
+
redundancy a model infers for free — *the decompressor is the model itself*. Proven
|
|
321
|
+
by hand on the OMEGA swarm: `MEMORY.md` 37→16KB (58%), `CLAUDE.md` 241→21KB
|
|
322
|
+
always-loaded (91%, archival).
|
|
323
|
+
|
|
324
|
+
**Opt-in by marker (fails safe).** A file is compressible only if it carries an
|
|
325
|
+
explicit marker; unmarked files are left untouched. The model's judgment is spent
|
|
326
|
+
once, in-session, authoring the marker — runtime is pure-Python marker parsing, no
|
|
327
|
+
model in the hot path.
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
<!-- swarph:compress lever=archival boundary="^## Session" -->
|
|
331
|
+
<!-- swarph:compress lever=shorthand pointer="](*.md)" floor=0.45 -->
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Two levers, different risk classes:**
|
|
335
|
+
|
|
336
|
+
| Lever | What | Loss class | Model? |
|
|
337
|
+
|---|---|---|---|
|
|
338
|
+
| `archival` | relocate the cold tail below `boundary` to `<file>.archive.<ext>` + leave a pointer | **lossless** (nothing destroyed) | no — pure Python, zero tokens |
|
|
339
|
+
| `shorthand` | rewrite a pointer-bearing INDEX to telegraphic shorthand | lossy, **bounded to index-over-preserved-source** (recoverable by construction) | yes (`claude -p` subscription path) |
|
|
340
|
+
|
|
341
|
+
Shorthand is gated: redundancy-floor (refuse if already dense), links-superset
|
|
342
|
+
(every `[]()` survives), index-over-source (every entry keeps a resolvable
|
|
343
|
+
pointer), and an **adversarial verify-expand** (an independent model hunts for a
|
|
344
|
+
dropped fact; one found → abort).
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
swarph compress MEMORY.md # dry-run: classify, propose, report savings
|
|
348
|
+
swarph compress MEMORY.md --apply # write (atomic tempfile→mv + .bak + verify-gate)
|
|
349
|
+
swarph compress MEMORY.md --verify-idempotent # assert compress(compress(x)) ≈ noop
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Dry-run is the default — nothing mutates without `--apply`. Cron-friendly exit codes:
|
|
353
|
+
|
|
354
|
+
| Code | Meaning |
|
|
355
|
+
|---|---|
|
|
356
|
+
| `0` | analyzed/savings-reported (or applied clean) |
|
|
357
|
+
| `2` | no such file |
|
|
358
|
+
| `3` | refused — unmarked (leave breathing) |
|
|
359
|
+
| `4` | refused — archival: no boundary line matched |
|
|
360
|
+
| `5` | refused — shorthand: below redundancy floor (already dense) |
|
|
361
|
+
| `6` | refused — shorthand dropped a link / lost a pointer-to-source |
|
|
362
|
+
| `7` | refused — adversarial verify-expand found a dropped fact |
|
|
363
|
+
| `8` | refused — not idempotent (second pass kept cutting; signal-eating alarm) |
|
|
364
|
+
|
|
365
|
+
Design spec: `docs/superpowers/specs/2026-06-11-swarph-context-compressor-design.md`
|
|
366
|
+
(in the hedge-fund-mcp repo).
|
|
367
|
+
|
|
316
368
|
### `--json` mode semantics
|
|
317
369
|
|
|
318
370
|
`--json` is a **harness trigger**, not a strict-validation gate. When set, swarph routes the response through the swarph-mesh JSON harness:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.10.
|
|
7
|
+
version = "0.10.2"
|
|
8
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.5: foolproof Windows auto-relaunch (genuine-WT detection via process ancestry, not WT_SESSION)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""`swarph compress <file>` — compress a machine-read surface. Dry-run by default;
|
|
2
|
+
marker opt-in (unmarked -> refuse). See docs spec 2026-06-11-swarph-context-compressor."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import argparse, asyncio, shutil, sys, tempfile, os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from ..compress.marker import parse_marker
|
|
7
|
+
from ..compress.levers import archival_split, shorthand
|
|
8
|
+
from ..compress import verify
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
12
|
+
p = argparse.ArgumentParser(prog="swarph compress", description="Compress a machine-read context surface.")
|
|
13
|
+
p.add_argument("file", help="path to the surface to compress")
|
|
14
|
+
p.add_argument("--apply", action="store_true", help="write changes (default: dry-run)")
|
|
15
|
+
p.add_argument("--verify-idempotent", action="store_true", help="assert compress(compress(x)) ~= noop")
|
|
16
|
+
p.add_argument("--force", action="store_true", help="override refusals (NOT for source-of-truth)")
|
|
17
|
+
return p
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _atomic_write(path: Path, content: str) -> None:
|
|
21
|
+
shutil.copy2(path, path.with_suffix(path.suffix + ".bak"))
|
|
22
|
+
fd, tmp = tempfile.mkstemp(dir=str(path.parent), suffix=".tmp")
|
|
23
|
+
with os.fdopen(fd, "w") as fh:
|
|
24
|
+
fh.write(content)
|
|
25
|
+
os.replace(tmp, path)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def run_compress(argv: list[str]) -> int:
|
|
29
|
+
args = _build_parser().parse_args(argv)
|
|
30
|
+
path = Path(args.file)
|
|
31
|
+
if not path.exists():
|
|
32
|
+
print(f"[compress] no such file: {path}", file=sys.stderr)
|
|
33
|
+
return 2
|
|
34
|
+
source = path.read_text()
|
|
35
|
+
marker = parse_marker(source)
|
|
36
|
+
if marker is None:
|
|
37
|
+
print(f"[compress] REFUSE: {path} carries no swarph:compress marker — leaving untouched", file=sys.stderr)
|
|
38
|
+
return 3
|
|
39
|
+
|
|
40
|
+
if marker.lever == "archival":
|
|
41
|
+
archive_path = path.with_suffix(".archive" + path.suffix)
|
|
42
|
+
res = archival_split(source, boundary=marker.boundary, archive_name=archive_path.name)
|
|
43
|
+
if res is None:
|
|
44
|
+
print(f"[compress] REFUSE: no boundary line matching {marker.boundary!r}", file=sys.stderr)
|
|
45
|
+
return 4
|
|
46
|
+
saved = len(source) - len(res.live)
|
|
47
|
+
print(f"[compress] archival: {path.name} {len(source)}B → {len(res.live)}B live "
|
|
48
|
+
f"(+{len(res.archive)}B → {archive_path.name}); saved {saved}B always-loaded")
|
|
49
|
+
if args.apply:
|
|
50
|
+
archive_path.write_text(res.archive)
|
|
51
|
+
_atomic_write(path, res.live)
|
|
52
|
+
print(f"[compress] applied (.bak left, archive {archive_path.name})")
|
|
53
|
+
return 0
|
|
54
|
+
|
|
55
|
+
# shorthand
|
|
56
|
+
floor = marker.floor if marker.floor is not None else 0.45
|
|
57
|
+
if not verify.above_floor(source, floor):
|
|
58
|
+
print(f"[compress] REFUSE: already dense (below redundancy floor {floor}) — nothing free to remove", file=sys.stderr)
|
|
59
|
+
return 5
|
|
60
|
+
out = asyncio.run(shorthand(source))
|
|
61
|
+
if not verify.links_preserved(source, out):
|
|
62
|
+
print("[compress] REFUSE: shorthand dropped a link (links not superset)", file=sys.stderr)
|
|
63
|
+
return 6
|
|
64
|
+
if not verify.entries_point_to_source(out, pointer=marker.pointer, base=path.parent):
|
|
65
|
+
print("[compress] REFUSE: an entry lost its pointer-to-source (index-over-source violated)", file=sys.stderr)
|
|
66
|
+
return 6
|
|
67
|
+
if not asyncio.run(verify.verify_expand(source, out)):
|
|
68
|
+
print("[compress] REFUSE: adversarial verify-expand found a dropped fact", file=sys.stderr)
|
|
69
|
+
return 7
|
|
70
|
+
if args.verify_idempotent:
|
|
71
|
+
out2 = asyncio.run(shorthand(out))
|
|
72
|
+
if not verify.idempotent(out, out2):
|
|
73
|
+
print("[compress] REFUSE: not idempotent — second pass kept cutting (signal-eating alarm)", file=sys.stderr)
|
|
74
|
+
return 8
|
|
75
|
+
saved = len(source) - len(out)
|
|
76
|
+
print(f"[compress] shorthand: {path.name} {len(source)}B → {len(out)}B; saved {saved}B ({saved*100//max(len(source),1)}%)")
|
|
77
|
+
if args.apply:
|
|
78
|
+
_atomic_write(path, out)
|
|
79
|
+
print("[compress] applied (.bak left)")
|
|
80
|
+
return 0
|
|
@@ -139,7 +139,15 @@ def run_init(argv: list[str]) -> int:
|
|
|
139
139
|
cwd_raw = args.cwd or (_ask("Working dir (cwd)", str(Path.cwd())) if interactive else str(Path.cwd()))
|
|
140
140
|
cwd = Path(cwd_raw).expanduser().resolve()
|
|
141
141
|
tmux = args.tmux or (_ask("tmux session", name) if interactive else name)
|
|
142
|
-
|
|
142
|
+
# Default MUST match where `swarph mesh sidecar` actually writes its
|
|
143
|
+
# cursor (<state-dir>/cursor.json, state-dir defaulting to
|
|
144
|
+
# ~/swarph_state/<name>/mesh-sidecar) — the watchdog reads THIS pin while
|
|
145
|
+
# the sidecar maintains THAT file. The old /tmp default left the two
|
|
146
|
+
# shipped components pointing at different paths out of the box
|
|
147
|
+
# (science-claude onboarding, 2026-06-10).
|
|
148
|
+
cursor = args.cursor or str(
|
|
149
|
+
Path.home() / "swarph_state" / name / "mesh-sidecar" / "cursor.json"
|
|
150
|
+
)
|
|
143
151
|
|
|
144
152
|
# ── sandbox ──
|
|
145
153
|
if provider == "codex":
|