@smilintux/skcapstone 0.4.4 → 0.4.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smilintux/skcapstone",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "SKCapstone - The sovereign agent framework. CapAuth identity, Cloud 9 trust, SKMemory persistence.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -212,7 +212,10 @@ class AgentCard(BaseModel):
212
212
  content = self.content_hash().encode("utf-8")
213
213
  pgp_message = pgpy.PGPMessage.new(content, cleartext=False)
214
214
 
215
- with key.unlock(passphrase):
215
+ if key.is_protected:
216
+ with key.unlock(passphrase):
217
+ sig = key.sign(pgp_message)
218
+ else:
216
219
  sig = key.sign(pgp_message)
217
220
 
218
221
  self.signature = str(sig)
@@ -48,20 +48,34 @@ def register_card_commands(main: click.Group) -> None:
48
48
  except FileNotFoundError:
49
49
  runtime = get_runtime(home_path)
50
50
  m = runtime.manifest
51
+ # Try to load public key from capauth
52
+ pub_key = ""
53
+ pub_path = Path(capauth_home).expanduser() / "identity" / "public.asc"
54
+ if pub_path.exists():
55
+ pub_key = pub_path.read_text(encoding="utf-8")
51
56
  agent_card = AgentCard.generate(
52
57
  name=m.name, fingerprint=m.identity.fingerprint or "unknown",
53
- public_key="", entity_type="ai",
58
+ public_key=pub_key, entity_type="ai",
54
59
  )
55
60
 
56
61
  if motto:
57
62
  agent_card.motto = motto
58
63
 
59
64
  if do_sign:
60
- if not passphrase:
61
- passphrase = click.prompt("PGP passphrase", hide_input=True)
62
65
  capauth_path = Path(capauth_home).expanduser()
63
66
  priv_path = capauth_path / "identity" / "private.asc"
64
67
  if priv_path.exists():
68
+ # Check if key is passphrase-protected before prompting
69
+ if not passphrase:
70
+ try:
71
+ import pgpy
72
+ key, _ = pgpy.PGPKey.from_file(str(priv_path))
73
+ if key.is_protected:
74
+ passphrase = click.prompt("PGP passphrase", hide_input=True)
75
+ else:
76
+ passphrase = ""
77
+ except Exception:
78
+ passphrase = click.prompt("PGP passphrase", hide_input=True)
65
79
  agent_card.sign(priv_path.read_text(encoding="utf-8"), passphrase)
66
80
  console.print("[green]Card signed.[/]")
67
81
  else:
@@ -50,19 +50,49 @@ def register_skills_commands(main: click.Group) -> None:
50
50
 
51
51
  skcapstone skills list --query identity --json
52
52
  """
53
- client = get_registry_client(registry)
54
- if client is None:
55
- console.print(
56
- "[bold red]skskills not installed.[/] "
57
- "Run: pip install skskills"
58
- )
59
- sys.exit(1)
53
+ # Try remote registry first, fall back to local catalog
54
+ skill_entries = None
55
+ source = "remote"
60
56
 
61
- try:
62
- skill_entries = client.search(query) if query else client.list_skills()
63
- except Exception as exc:
64
- console.print(f"[bold red]Registry error:[/] {exc}")
65
- sys.exit(1)
57
+ client = get_registry_client(registry)
58
+ if client is not None:
59
+ try:
60
+ skill_entries = client.search(query) if query else client.list_skills()
61
+ except Exception:
62
+ pass # fall through to local catalog
63
+
64
+ # Fall back to local catalog (bundled with skskills)
65
+ if skill_entries is None:
66
+ try:
67
+ from skskills.catalog import SkillCatalog
68
+
69
+ catalog = SkillCatalog()
70
+ if query:
71
+ entries = catalog.search(query)
72
+ else:
73
+ entries = catalog.list_all()
74
+ skill_entries = [
75
+ {
76
+ "name": e.name,
77
+ "version": "",
78
+ "description": e.description,
79
+ "tags": e.tags,
80
+ "category": e.category,
81
+ "pip": e.pip,
82
+ "git": e.git,
83
+ }
84
+ for e in entries
85
+ ]
86
+ source = "catalog"
87
+ except ImportError:
88
+ console.print(
89
+ "[bold red]skskills not installed.[/] "
90
+ "Run: pip install skskills"
91
+ )
92
+ sys.exit(1)
93
+ except Exception as exc:
94
+ console.print(f"[bold red]Catalog error:[/] {exc}")
95
+ sys.exit(1)
66
96
 
67
97
  if json_out:
68
98
  click.echo(json.dumps(skill_entries, indent=2))
@@ -76,17 +106,19 @@ def register_skills_commands(main: click.Group) -> None:
76
106
  label = f"[bold]{len(skill_entries)}[/] skill(s)"
77
107
  if query:
78
108
  label += f" matching [cyan]'{query}'[/]"
109
+ if source == "catalog":
110
+ label += " [dim](local catalog)[/]"
79
111
 
80
112
  table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
81
113
  table.add_column("Name", style="cyan")
82
- table.add_column("Version", style="dim")
114
+ table.add_column("Category", style="dim")
83
115
  table.add_column("Description")
84
116
  table.add_column("Tags", style="dim")
85
117
 
86
118
  for s in skill_entries:
87
119
  table.add_row(
88
120
  s.get("name", ""),
89
- s.get("version", ""),
121
+ s.get("category", s.get("version", "")),
90
122
  s.get("description", ""),
91
123
  ", ".join(s.get("tags", [])),
92
124
  )