@smilintux/skcapstone 0.1.0
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.
- package/.cursorrules +33 -0
- package/.github/workflows/ci.yml +23 -0
- package/.github/workflows/publish.yml +52 -0
- package/AGENTS.md +74 -0
- package/CLAUDE.md +56 -0
- package/LICENSE +674 -0
- package/README.md +242 -0
- package/SKILL.md +36 -0
- package/bin/cli.js +18 -0
- package/docs/ARCHITECTURE.md +510 -0
- package/docs/SECURITY_DESIGN.md +315 -0
- package/docs/SOVEREIGN_SINGULARITY.md +371 -0
- package/docs/TOKEN_SYSTEM.md +201 -0
- package/index.d.ts +9 -0
- package/index.js +32 -0
- package/package.json +32 -0
- package/pyproject.toml +84 -0
- package/src/skcapstone/__init__.py +13 -0
- package/src/skcapstone/cli.py +1441 -0
- package/src/skcapstone/connectors/__init__.py +6 -0
- package/src/skcapstone/coordination.py +590 -0
- package/src/skcapstone/discovery.py +275 -0
- package/src/skcapstone/memory_engine.py +457 -0
- package/src/skcapstone/models.py +223 -0
- package/src/skcapstone/pillars/__init__.py +8 -0
- package/src/skcapstone/pillars/identity.py +91 -0
- package/src/skcapstone/pillars/memory.py +61 -0
- package/src/skcapstone/pillars/security.py +83 -0
- package/src/skcapstone/pillars/sync.py +486 -0
- package/src/skcapstone/pillars/trust.py +335 -0
- package/src/skcapstone/runtime.py +190 -0
- package/src/skcapstone/skills/__init__.py +1 -0
- package/src/skcapstone/skills/syncthing_setup.py +297 -0
- package/src/skcapstone/sync/__init__.py +14 -0
- package/src/skcapstone/sync/backends.py +330 -0
- package/src/skcapstone/sync/engine.py +301 -0
- package/src/skcapstone/sync/models.py +97 -0
- package/src/skcapstone/sync/vault.py +284 -0
- package/src/skcapstone/tokens.py +439 -0
- package/tests/__init__.py +0 -0
- package/tests/conftest.py +42 -0
- package/tests/test_coordination.py +299 -0
- package/tests/test_discovery.py +57 -0
- package/tests/test_memory_engine.py +391 -0
- package/tests/test_models.py +63 -0
- package/tests/test_pillars.py +87 -0
- package/tests/test_runtime.py +60 -0
- package/tests/test_sync.py +507 -0
- package/tests/test_syncthing_setup.py +76 -0
- package/tests/test_tokens.py +265 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Identity pillar — CapAuth integration.
|
|
3
|
+
|
|
4
|
+
PGP-based sovereign identity. The agent IS its key.
|
|
5
|
+
No corporate SSO. No OAuth dance. Cryptographic proof of self.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import subprocess
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
from ..models import IdentityState, PillarStatus
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_identity(
|
|
20
|
+
home: Path,
|
|
21
|
+
name: str,
|
|
22
|
+
email: Optional[str] = None,
|
|
23
|
+
) -> IdentityState:
|
|
24
|
+
"""Generate a new sovereign identity for the agent.
|
|
25
|
+
|
|
26
|
+
Tries CapAuth first (full PGP key generation).
|
|
27
|
+
Falls back to recording identity metadata without key material.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
home: Agent home directory (~/.skcapstone).
|
|
31
|
+
name: Agent display name.
|
|
32
|
+
email: Optional email for the identity.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
IdentityState with the new identity.
|
|
36
|
+
"""
|
|
37
|
+
identity_dir = home / "identity"
|
|
38
|
+
identity_dir.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
|
|
40
|
+
state = IdentityState(
|
|
41
|
+
name=name,
|
|
42
|
+
email=email or f"{name.lower().replace(' ', '-')}@skcapstone.local",
|
|
43
|
+
created_at=datetime.now(timezone.utc),
|
|
44
|
+
status=PillarStatus.DEGRADED,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
from capauth.keys import generate_keypair # type: ignore[import-untyped]
|
|
49
|
+
|
|
50
|
+
pub_key, fingerprint = generate_keypair(
|
|
51
|
+
name=name,
|
|
52
|
+
email=state.email,
|
|
53
|
+
output_dir=str(identity_dir),
|
|
54
|
+
)
|
|
55
|
+
state.fingerprint = fingerprint
|
|
56
|
+
state.key_path = identity_dir / "agent.pub"
|
|
57
|
+
state.status = PillarStatus.ACTIVE
|
|
58
|
+
except (ImportError, Exception):
|
|
59
|
+
# Reason: CapAuth not installed or key generation failed —
|
|
60
|
+
# record identity metadata anyway so agent has a name
|
|
61
|
+
state.fingerprint = _generate_placeholder_fingerprint(name)
|
|
62
|
+
state.status = PillarStatus.DEGRADED
|
|
63
|
+
|
|
64
|
+
identity_manifest = {
|
|
65
|
+
"name": state.name,
|
|
66
|
+
"email": state.email,
|
|
67
|
+
"fingerprint": state.fingerprint,
|
|
68
|
+
"created_at": state.created_at.isoformat() if state.created_at else None,
|
|
69
|
+
"capauth_managed": state.status == PillarStatus.ACTIVE,
|
|
70
|
+
}
|
|
71
|
+
(identity_dir / "identity.json").write_text(json.dumps(identity_manifest, indent=2))
|
|
72
|
+
|
|
73
|
+
return state
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _generate_placeholder_fingerprint(name: str) -> str:
|
|
77
|
+
"""Generate a deterministic placeholder fingerprint from the agent name.
|
|
78
|
+
|
|
79
|
+
Not cryptographic — just a consistent identifier until CapAuth
|
|
80
|
+
is installed and proper PGP keys are generated.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
name: Agent display name.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
A hex string resembling a fingerprint.
|
|
87
|
+
"""
|
|
88
|
+
import hashlib
|
|
89
|
+
|
|
90
|
+
digest = hashlib.sha256(f"skcapstone:{name}".encode()).hexdigest()
|
|
91
|
+
return digest[:40].upper()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory pillar — sovereign memory initialization.
|
|
3
|
+
|
|
4
|
+
Persistent context across platforms and sessions.
|
|
5
|
+
The agent remembers. Always. Everywhere.
|
|
6
|
+
|
|
7
|
+
The built-in memory engine (memory_engine.py) provides full
|
|
8
|
+
store/search/recall/list/gc capabilities. The optional external
|
|
9
|
+
`skmemory` package adds legacy compatibility but is NOT required.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from ..models import MemoryLayer, MemoryState, PillarStatus
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def initialize_memory(home: Path, memory_home: Optional[Path] = None) -> MemoryState:
|
|
21
|
+
"""Initialize memory for the agent.
|
|
22
|
+
|
|
23
|
+
Creates the memory directory structure with layer subdirs.
|
|
24
|
+
The built-in memory engine handles all operations; no
|
|
25
|
+
external package required.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
home: Agent home directory (~/.skcapstone).
|
|
29
|
+
memory_home: Unused, kept for backward compatibility.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
MemoryState after initialization.
|
|
33
|
+
"""
|
|
34
|
+
memory_dir = home / "memory"
|
|
35
|
+
memory_dir.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
|
|
37
|
+
for layer in MemoryLayer:
|
|
38
|
+
(memory_dir / layer.value).mkdir(parents=True, exist_ok=True)
|
|
39
|
+
|
|
40
|
+
state = MemoryState(store_path=memory_dir, status=PillarStatus.ACTIVE)
|
|
41
|
+
return state
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_memory_stats(home: Path) -> dict:
|
|
45
|
+
"""Get current memory statistics from the built-in engine.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
home: Agent home directory (~/.skcapstone).
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Dict with memory layer counts.
|
|
52
|
+
"""
|
|
53
|
+
from ..memory_engine import get_stats
|
|
54
|
+
|
|
55
|
+
stats = get_stats(home)
|
|
56
|
+
return {
|
|
57
|
+
"short_term": stats.short_term,
|
|
58
|
+
"mid_term": stats.mid_term,
|
|
59
|
+
"long_term": stats.long_term,
|
|
60
|
+
"total": stats.total_memories,
|
|
61
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Security pillar — SKSecurity integration.
|
|
3
|
+
|
|
4
|
+
Audit everything. Detect threats. Protect the sovereign.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from ..models import PillarStatus, SecurityState
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def initialize_security(home: Path) -> SecurityState:
|
|
17
|
+
"""Initialize security layer for the agent.
|
|
18
|
+
|
|
19
|
+
Creates audit log structure and baseline security config.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
home: Agent home directory (~/.skcapstone).
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
SecurityState after initialization.
|
|
26
|
+
"""
|
|
27
|
+
security_dir = home / "security"
|
|
28
|
+
security_dir.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
|
|
30
|
+
state = SecurityState()
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
import sksecurity # type: ignore[import-untyped]
|
|
34
|
+
|
|
35
|
+
state.status = PillarStatus.DEGRADED
|
|
36
|
+
except ImportError:
|
|
37
|
+
security_config = {
|
|
38
|
+
"note": "Install sksecurity (pip install sksecurity) for full security",
|
|
39
|
+
"audit_enabled": True,
|
|
40
|
+
}
|
|
41
|
+
(security_dir / "security.json").write_text(json.dumps(security_config, indent=2))
|
|
42
|
+
state.status = PillarStatus.DEGRADED
|
|
43
|
+
_init_audit_log(security_dir)
|
|
44
|
+
return state
|
|
45
|
+
|
|
46
|
+
_init_audit_log(security_dir)
|
|
47
|
+
|
|
48
|
+
baseline = {
|
|
49
|
+
"threats_detected": 0,
|
|
50
|
+
"last_scan": None,
|
|
51
|
+
"audit_enabled": True,
|
|
52
|
+
"initialized_at": datetime.now(timezone.utc).isoformat(),
|
|
53
|
+
}
|
|
54
|
+
(security_dir / "security.json").write_text(json.dumps(baseline, indent=2))
|
|
55
|
+
|
|
56
|
+
return state
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _init_audit_log(security_dir: Path) -> None:
|
|
60
|
+
"""Create the audit log file with a header entry."""
|
|
61
|
+
audit_log = security_dir / "audit.log"
|
|
62
|
+
if not audit_log.exists():
|
|
63
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
64
|
+
audit_log.write_text(f"[{timestamp}] INIT — SKCapstone security audit log created\n")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def audit_event(home: Path, event_type: str, detail: str) -> None:
|
|
68
|
+
"""Append an event to the audit log.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
home: Agent home directory.
|
|
72
|
+
event_type: Event category (INIT, AUTH, MEMORY, TRUST, etc.).
|
|
73
|
+
detail: Human-readable event description.
|
|
74
|
+
"""
|
|
75
|
+
security_dir = home / "security"
|
|
76
|
+
security_dir.mkdir(parents=True, exist_ok=True)
|
|
77
|
+
audit_log = security_dir / "audit.log"
|
|
78
|
+
|
|
79
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
80
|
+
entry = f"[{timestamp}] {event_type} — {detail}\n"
|
|
81
|
+
|
|
82
|
+
with audit_log.open("a") as f:
|
|
83
|
+
f.write(entry)
|