@smilintux/skcapstone 0.4.6 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smilintux/skcapstone",
3
- "version": "0.4.6",
3
+ "version": "0.9.0",
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",
@@ -86,6 +86,7 @@ from .search_cmd import register_search_commands
86
86
  from .mood_cmd import register_mood_commands
87
87
  from .register_cmd import register_register_commands
88
88
  from .gtd import register_gtd_commands
89
+ from .itil import register_itil_commands
89
90
  from .skseed import register_skseed_commands
90
91
  from .service_cmd import register_service_commands
91
92
  from .telegram import register_telegram_commands
@@ -138,6 +139,7 @@ register_search_commands(main)
138
139
  register_mood_commands(main)
139
140
  register_register_commands(main)
140
141
  register_gtd_commands(main)
142
+ register_itil_commands(main)
141
143
  register_skseed_commands(main)
142
144
  register_service_commands(main)
143
145
  register_telegram_commands(main)
@@ -0,0 +1,434 @@
1
+ """ITIL service management CLI commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ from pathlib import Path
8
+
9
+ import click
10
+
11
+ from ._common import AGENT_HOME, SHARED_ROOT, console
12
+
13
+
14
+ def register_itil_commands(main: click.Group) -> None:
15
+ """Register the itil command group."""
16
+
17
+ @main.group()
18
+ def itil():
19
+ """ITIL service management — incidents, problems, changes."""
20
+
21
+ # ── itil status ───────────────────────────────────────────────────
22
+
23
+ @itil.command("status")
24
+ def itil_status():
25
+ """Show ITIL dashboard: open incidents, active problems, pending changes."""
26
+ from ..itil import ITILManager
27
+
28
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
29
+ status = mgr.get_status()
30
+
31
+ inc = status["incidents"]
32
+ prb = status["problems"]
33
+ chg = status["changes"]
34
+ kedb = status["kedb"]
35
+
36
+ console.print(f"\n[bold]ITIL Dashboard[/bold]")
37
+ console.print(f" Incidents: [red]{inc['open']}[/red] open / {inc['total']} total")
38
+ for sev, count in inc.get("by_severity", {}).items():
39
+ if count:
40
+ console.print(f" {sev}: {count}")
41
+ console.print(f" Problems: [yellow]{prb['active']}[/yellow] active / {prb['total']} total")
42
+ console.print(f" Changes: [blue]{chg['pending']}[/blue] pending / {chg['total']} total")
43
+ console.print(f" KEDB: {kedb['total']} entries")
44
+
45
+ if inc["open_list"]:
46
+ console.print(f"\n[bold red]Open Incidents:[/bold red]")
47
+ for i in inc["open_list"]:
48
+ console.print(
49
+ f" [{i['id']}] {i['severity'].upper()} {i['title']} "
50
+ f"({i['status']}) @{i['managed_by']}"
51
+ )
52
+
53
+ if chg["pending_list"]:
54
+ console.print(f"\n[bold blue]Pending Changes:[/bold blue]")
55
+ for c in chg["pending_list"]:
56
+ console.print(
57
+ f" [{c['id']}] {c['title']} ({c['status']}, "
58
+ f"{c['change_type']}) @{c['managed_by']}"
59
+ )
60
+
61
+ console.print()
62
+
63
+ # ── itil incident ─────────────────────────────────────────────────
64
+
65
+ @itil.group()
66
+ def incident():
67
+ """Incident management."""
68
+
69
+ @incident.command("create")
70
+ @click.option("--title", "-t", required=True, help="Incident title")
71
+ @click.option(
72
+ "--severity", "-s", default="sev3",
73
+ type=click.Choice(["sev1", "sev2", "sev3", "sev4"]),
74
+ help="Severity level",
75
+ )
76
+ @click.option("--service", multiple=True, help="Affected service(s)")
77
+ @click.option("--impact", default="", help="Business impact")
78
+ @click.option("--by", "managed_by", default="human", help="Managing agent")
79
+ @click.option("--tag", multiple=True, help="Tags")
80
+ def incident_create(title, severity, service, impact, managed_by, tag):
81
+ """Create a new incident."""
82
+ from ..itil import ITILManager
83
+
84
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
85
+ inc = mgr.create_incident(
86
+ title=title,
87
+ severity=severity,
88
+ affected_services=list(service),
89
+ impact=impact,
90
+ managed_by=managed_by,
91
+ created_by=managed_by,
92
+ tags=list(tag),
93
+ )
94
+ console.print(
95
+ f"\n [green]Created:[/green] {inc.id} — {inc.title} "
96
+ f"({inc.severity.value}, {inc.status.value})"
97
+ )
98
+ if inc.gtd_item_ids:
99
+ console.print(f" [dim]GTD item(s): {', '.join(inc.gtd_item_ids)}[/dim]")
100
+ console.print()
101
+
102
+ @incident.command("list")
103
+ @click.option(
104
+ "--status", type=click.Choice([
105
+ "detected", "acknowledged", "investigating",
106
+ "escalated", "resolved", "closed",
107
+ ]),
108
+ help="Filter by status",
109
+ )
110
+ @click.option(
111
+ "--severity",
112
+ type=click.Choice(["sev1", "sev2", "sev3", "sev4"]),
113
+ help="Filter by severity",
114
+ )
115
+ @click.option("--service", help="Filter by affected service")
116
+ def incident_list(status, severity, service):
117
+ """List incidents."""
118
+ from ..itil import ITILManager
119
+
120
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
121
+ incidents = mgr.list_incidents(status=status, severity=severity, service=service)
122
+
123
+ if not incidents:
124
+ console.print("\n [dim]No incidents found[/dim]\n")
125
+ return
126
+
127
+ console.print(f"\n[bold]Incidents ({len(incidents)}):[/bold]")
128
+ for i in incidents:
129
+ sev = i.severity.value.upper()
130
+ console.print(
131
+ f" [{i.id}] {sev} {i.title} ({i.status.value}) @{i.managed_by}"
132
+ )
133
+ console.print()
134
+
135
+ @incident.command("update")
136
+ @click.argument("incident_id")
137
+ @click.option("--agent", default="human", help="Agent making the update")
138
+ @click.option(
139
+ "--status", "new_status",
140
+ type=click.Choice([
141
+ "acknowledged", "investigating", "escalated", "resolved", "closed",
142
+ ]),
143
+ help="New status",
144
+ )
145
+ @click.option(
146
+ "--severity",
147
+ type=click.Choice(["sev1", "sev2", "sev3", "sev4"]),
148
+ help="New severity",
149
+ )
150
+ @click.option("--note", default="", help="Timeline note")
151
+ @click.option("--resolution", default=None, help="Resolution summary")
152
+ def incident_update(incident_id, agent, new_status, severity, note, resolution):
153
+ """Update an incident status or metadata."""
154
+ from ..itil import ITILManager
155
+
156
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
157
+ try:
158
+ inc = mgr.update_incident(
159
+ incident_id=incident_id,
160
+ agent=agent,
161
+ new_status=new_status,
162
+ severity=severity,
163
+ note=note,
164
+ resolution_summary=resolution,
165
+ )
166
+ console.print(
167
+ f"\n [green]Updated:[/green] {inc.id} -> {inc.status.value} "
168
+ f"({inc.severity.value})\n"
169
+ )
170
+ except ValueError as exc:
171
+ console.print(f"\n [red]Error:[/red] {exc}\n")
172
+
173
+ # ── itil problem ──────────────────────────────────────────────────
174
+
175
+ @itil.group()
176
+ def problem():
177
+ """Problem management."""
178
+
179
+ @problem.command("create")
180
+ @click.option("--title", "-t", required=True, help="Problem title")
181
+ @click.option("--by", "managed_by", default="human", help="Managing agent")
182
+ @click.option("--incident", "incident_ids", multiple=True, help="Related incident ID(s)")
183
+ @click.option("--workaround", default="", help="Known workaround")
184
+ @click.option("--tag", multiple=True, help="Tags")
185
+ def problem_create(title, managed_by, incident_ids, workaround, tag):
186
+ """Create a new problem record."""
187
+ from ..itil import ITILManager
188
+
189
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
190
+ prb = mgr.create_problem(
191
+ title=title,
192
+ managed_by=managed_by,
193
+ created_by=managed_by,
194
+ related_incident_ids=list(incident_ids),
195
+ workaround=workaround,
196
+ tags=list(tag),
197
+ )
198
+ console.print(
199
+ f"\n [green]Created:[/green] {prb.id} — {prb.title} ({prb.status.value})\n"
200
+ )
201
+
202
+ @problem.command("list")
203
+ @click.option(
204
+ "--status",
205
+ type=click.Choice(["identified", "analyzing", "known_error", "resolved"]),
206
+ help="Filter by status",
207
+ )
208
+ def problem_list(status):
209
+ """List problems."""
210
+ from ..itil import ITILManager
211
+
212
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
213
+ problems = mgr.list_problems(status=status)
214
+
215
+ if not problems:
216
+ console.print("\n [dim]No problems found[/dim]\n")
217
+ return
218
+
219
+ console.print(f"\n[bold]Problems ({len(problems)}):[/bold]")
220
+ for p in problems:
221
+ console.print(
222
+ f" [{p.id}] {p.title} ({p.status.value}) @{p.managed_by}"
223
+ )
224
+ console.print()
225
+
226
+ @problem.command("update")
227
+ @click.argument("problem_id")
228
+ @click.option("--agent", default="human", help="Agent making the update")
229
+ @click.option(
230
+ "--status", "new_status",
231
+ type=click.Choice(["analyzing", "known_error", "resolved"]),
232
+ help="New status",
233
+ )
234
+ @click.option("--root-cause", default=None, help="Root cause description")
235
+ @click.option("--workaround", default=None, help="Workaround")
236
+ @click.option("--note", default="", help="Timeline note")
237
+ @click.option("--create-kedb", is_flag=True, help="Create KEDB entry")
238
+ def problem_update(problem_id, agent, new_status, root_cause, workaround, note, create_kedb):
239
+ """Update a problem record."""
240
+ from ..itil import ITILManager
241
+
242
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
243
+ try:
244
+ prb = mgr.update_problem(
245
+ problem_id=problem_id,
246
+ agent=agent,
247
+ new_status=new_status,
248
+ root_cause=root_cause,
249
+ workaround=workaround,
250
+ note=note,
251
+ create_kedb=create_kedb,
252
+ )
253
+ console.print(
254
+ f"\n [green]Updated:[/green] {prb.id} -> {prb.status.value}\n"
255
+ )
256
+ if prb.kedb_id:
257
+ console.print(f" [dim]KEDB entry: {prb.kedb_id}[/dim]\n")
258
+ except ValueError as exc:
259
+ console.print(f"\n [red]Error:[/red] {exc}\n")
260
+
261
+ # ── itil change ───────────────────────────────────────────────────
262
+
263
+ @itil.group()
264
+ def change():
265
+ """Change management (RFC)."""
266
+
267
+ @change.command("propose")
268
+ @click.option("--title", "-t", required=True, help="Change title")
269
+ @click.option(
270
+ "--type", "change_type", default="normal",
271
+ type=click.Choice(["standard", "normal", "emergency"]),
272
+ help="Change type",
273
+ )
274
+ @click.option(
275
+ "--risk", default="medium",
276
+ type=click.Choice(["low", "medium", "high"]),
277
+ help="Risk level",
278
+ )
279
+ @click.option("--rollback", default="", help="Rollback plan")
280
+ @click.option("--test-plan", default="", help="Test plan")
281
+ @click.option("--by", "managed_by", default="human", help="Managing agent")
282
+ @click.option("--implementer", default=None, help="Implementing agent")
283
+ @click.option("--problem", "related_problem_id", default=None, help="Related problem ID")
284
+ @click.option("--tag", multiple=True, help="Tags")
285
+ def change_propose(title, change_type, risk, rollback, test_plan,
286
+ managed_by, implementer, related_problem_id, tag):
287
+ """Propose a new change (RFC)."""
288
+ from ..itil import ITILManager
289
+
290
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
291
+ chg = mgr.propose_change(
292
+ title=title,
293
+ change_type=change_type,
294
+ risk=risk,
295
+ rollback_plan=rollback,
296
+ test_plan=test_plan,
297
+ managed_by=managed_by,
298
+ created_by=managed_by,
299
+ implementer=implementer,
300
+ related_problem_id=related_problem_id,
301
+ tags=list(tag),
302
+ )
303
+ console.print(
304
+ f"\n [green]Proposed:[/green] {chg.id} — {chg.title} "
305
+ f"({chg.change_type.value}, {chg.status.value})\n"
306
+ )
307
+
308
+ @change.command("list")
309
+ @click.option(
310
+ "--status",
311
+ type=click.Choice([
312
+ "proposed", "reviewing", "approved", "rejected",
313
+ "implementing", "deployed", "verified", "failed", "closed",
314
+ ]),
315
+ help="Filter by status",
316
+ )
317
+ def change_list(status):
318
+ """List changes."""
319
+ from ..itil import ITILManager
320
+
321
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
322
+ changes = mgr.list_changes(status=status)
323
+
324
+ if not changes:
325
+ console.print("\n [dim]No changes found[/dim]\n")
326
+ return
327
+
328
+ console.print(f"\n[bold]Changes ({len(changes)}):[/bold]")
329
+ for c in changes:
330
+ console.print(
331
+ f" [{c.id}] {c.title} ({c.status.value}, "
332
+ f"{c.change_type.value}) @{c.managed_by}"
333
+ )
334
+ console.print()
335
+
336
+ @change.command("update")
337
+ @click.argument("change_id")
338
+ @click.option("--agent", default="human", help="Agent making the update")
339
+ @click.option(
340
+ "--status", "new_status",
341
+ type=click.Choice([
342
+ "reviewing", "approved", "rejected", "implementing",
343
+ "deployed", "verified", "failed", "closed",
344
+ ]),
345
+ help="New status",
346
+ )
347
+ @click.option("--note", default="", help="Timeline note")
348
+ def change_update(change_id, agent, new_status, note):
349
+ """Update a change status."""
350
+ from ..itil import ITILManager
351
+
352
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
353
+ try:
354
+ chg = mgr.update_change(
355
+ change_id=change_id,
356
+ agent=agent,
357
+ new_status=new_status,
358
+ note=note,
359
+ )
360
+ console.print(
361
+ f"\n [green]Updated:[/green] {chg.id} -> {chg.status.value}\n"
362
+ )
363
+ except ValueError as exc:
364
+ console.print(f"\n [red]Error:[/red] {exc}\n")
365
+
366
+ # ── itil cab ──────────────────────────────────────────────────────
367
+
368
+ @itil.group()
369
+ def cab():
370
+ """Change Advisory Board voting."""
371
+
372
+ @cab.command("vote")
373
+ @click.argument("change_id")
374
+ @click.option("--agent", default="human", help="Voting agent")
375
+ @click.option(
376
+ "--decision", default="approved",
377
+ type=click.Choice(["approved", "rejected", "abstain"]),
378
+ help="Vote decision",
379
+ )
380
+ @click.option("--conditions", default="", help="Approval conditions")
381
+ def cab_vote(change_id, agent, decision, conditions):
382
+ """Submit a CAB vote for a change."""
383
+ from ..itil import ITILManager
384
+
385
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
386
+ vote = mgr.submit_cab_vote(
387
+ change_id=change_id,
388
+ agent=agent,
389
+ decision=decision,
390
+ conditions=conditions,
391
+ )
392
+ console.print(
393
+ f"\n [green]Voted:[/green] {vote.agent} -> {vote.decision.value} "
394
+ f"on {vote.change_id}\n"
395
+ )
396
+
397
+ # ── itil kedb ─────────────────────────────────────────────────────
398
+
399
+ @itil.group()
400
+ def kedb():
401
+ """Known Error Database."""
402
+
403
+ @kedb.command("search")
404
+ @click.argument("query")
405
+ def kedb_search(query):
406
+ """Search the Known Error Database."""
407
+ from ..itil import ITILManager
408
+
409
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
410
+ results = mgr.search_kedb(query)
411
+
412
+ if not results:
413
+ console.print(f"\n [dim]No KEDB entries matching '{query}'[/dim]\n")
414
+ return
415
+
416
+ console.print(f"\n[bold]KEDB Results ({len(results)}):[/bold]")
417
+ for e in results:
418
+ console.print(f" [{e.id}] {e.title}")
419
+ if e.workaround:
420
+ console.print(f" [dim]Workaround: {e.workaround[:100]}[/dim]")
421
+ if e.root_cause:
422
+ console.print(f" [dim]Root cause: {e.root_cause[:100]}[/dim]")
423
+ console.print()
424
+
425
+ # ── itil board ────────────────────────────────────────────────────
426
+
427
+ @itil.command("board")
428
+ def itil_board():
429
+ """Generate ITIL-BOARD.md overview."""
430
+ from ..itil import ITILManager
431
+
432
+ mgr = ITILManager(Path(SHARED_ROOT).expanduser())
433
+ path = mgr.write_board_md()
434
+ console.print(f"\n [green]Generated:[/green] {path}\n")
@@ -117,3 +117,30 @@ def write_default_config(home: Path) -> Path:
117
117
  config_path.write_text(header + content, encoding="utf-8")
118
118
  logger.info("Wrote default consciousness config to %s", config_path)
119
119
  return config_path
120
+
121
+
122
+ def load_dreaming_config(
123
+ home: Path,
124
+ config_path: Optional[Path] = None,
125
+ ):
126
+ """Load dreaming config from the consciousness.yaml ``dreaming:`` section.
127
+
128
+ Args:
129
+ home: Agent home directory.
130
+ config_path: Explicit path to config file (overrides default).
131
+
132
+ Returns:
133
+ DreamingConfig (defaults if section is missing or unparseable).
134
+ """
135
+ from .dreaming import DreamingConfig
136
+
137
+ yaml_path = config_path or (home / "config" / CONFIG_FILENAME)
138
+ if not yaml_path.exists():
139
+ return DreamingConfig()
140
+ try:
141
+ raw = yaml.safe_load(yaml_path.read_text(encoding="utf-8"))
142
+ if raw and isinstance(raw, dict) and "dreaming" in raw:
143
+ return DreamingConfig.model_validate(raw["dreaming"])
144
+ except Exception as exc:
145
+ logger.warning("Failed to parse dreaming config: %s", exc)
146
+ return DreamingConfig()
@@ -123,6 +123,7 @@ class AgentFile(BaseModel):
123
123
  claimed_tasks: list[str] = Field(default_factory=list)
124
124
  completed_tasks: list[str] = Field(default_factory=list)
125
125
  capabilities: list[str] = Field(default_factory=list)
126
+ itil_claims: list[str] = Field(default_factory=list)
126
127
  notes: str = ""
127
128
 
128
129