agent-devkit 0.2.0 → 0.3.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.
Files changed (172) hide show
  1. package/README.md +48 -6
  2. package/bin/agent.mjs +133 -7
  3. package/package.json +1 -1
  4. package/runtime/README.md +187 -5
  5. package/runtime/agent +31 -5
  6. package/runtime/agents/README.md +18 -0
  7. package/runtime/agents/contribution-reviewer/AGENTS.md +8 -0
  8. package/runtime/agents/contribution-reviewer/README.md +8 -0
  9. package/runtime/agents/contribution-reviewer/agent.yaml +40 -0
  10. package/runtime/agents/contribution-reviewer/capabilities/plan-contribution-pr/capability.yaml +27 -0
  11. package/runtime/agents/contribution-reviewer/capabilities/plan-contribution-pr/decision-rules.md +5 -0
  12. package/runtime/agents/contribution-reviewer/capabilities/plan-contribution-pr/workflow.md +6 -0
  13. package/runtime/agents/contribution-reviewer/capabilities/review-contribution/capability.yaml +25 -0
  14. package/runtime/agents/contribution-reviewer/capabilities/review-contribution/decision-rules.md +5 -0
  15. package/runtime/agents/contribution-reviewer/capabilities/review-contribution/workflow.md +5 -0
  16. package/runtime/agents/contribution-reviewer/capabilities/validate-local-contribution/capability.yaml +26 -0
  17. package/runtime/agents/contribution-reviewer/capabilities/validate-local-contribution/decision-rules.md +5 -0
  18. package/runtime/agents/contribution-reviewer/capabilities/validate-local-contribution/workflow.md +6 -0
  19. package/runtime/agents/contribution-reviewer/infra/README.md +6 -0
  20. package/runtime/agents/contribution-reviewer/knowledge/context.md +8 -0
  21. package/runtime/agents/contribution-reviewer/knowledge/system.md +8 -0
  22. package/runtime/agents/contribution-reviewer/templates/README.md +3 -0
  23. package/runtime/agents/knowledge-author/AGENTS.md +7 -0
  24. package/runtime/agents/knowledge-author/README.md +7 -0
  25. package/runtime/agents/knowledge-author/agent.yaml +37 -0
  26. package/runtime/agents/knowledge-author/capabilities/create-knowledge-snapshot/capability.yaml +30 -0
  27. package/runtime/agents/knowledge-author/capabilities/create-knowledge-snapshot/decision-rules.md +6 -0
  28. package/runtime/agents/knowledge-author/capabilities/create-knowledge-snapshot/workflow.md +7 -0
  29. package/runtime/agents/knowledge-author/infra/.gitkeep +1 -0
  30. package/runtime/agents/knowledge-author/knowledge/context.md +4 -0
  31. package/runtime/agents/knowledge-author/knowledge/system.md +4 -0
  32. package/runtime/agents/knowledge-author/templates/.gitkeep +1 -0
  33. package/runtime/agents/knowledge-curator/AGENTS.md +7 -0
  34. package/runtime/agents/knowledge-curator/README.md +6 -0
  35. package/runtime/agents/knowledge-curator/agent.yaml +37 -0
  36. package/runtime/agents/knowledge-curator/capabilities/curate-knowledge-base/capability.yaml +29 -0
  37. package/runtime/agents/knowledge-curator/capabilities/curate-knowledge-base/decision-rules.md +6 -0
  38. package/runtime/agents/knowledge-curator/capabilities/curate-knowledge-base/workflow.md +7 -0
  39. package/runtime/agents/knowledge-curator/infra/.gitkeep +1 -0
  40. package/runtime/agents/knowledge-curator/knowledge/context.md +4 -0
  41. package/runtime/agents/knowledge-curator/knowledge/system.md +4 -0
  42. package/runtime/agents/knowledge-curator/templates/.gitkeep +1 -0
  43. package/runtime/agents/knowledge-infra-builder/AGENTS.md +8 -0
  44. package/runtime/agents/knowledge-infra-builder/README.md +8 -0
  45. package/runtime/agents/knowledge-infra-builder/agent.yaml +38 -0
  46. package/runtime/agents/knowledge-infra-builder/capabilities/create-knowledge-base/capability.yaml +30 -0
  47. package/runtime/agents/knowledge-infra-builder/capabilities/create-knowledge-base/decision-rules.md +6 -0
  48. package/runtime/agents/knowledge-infra-builder/capabilities/create-knowledge-base/workflow.md +7 -0
  49. package/runtime/agents/knowledge-infra-builder/infra/.gitkeep +1 -0
  50. package/runtime/agents/knowledge-infra-builder/knowledge/context.md +4 -0
  51. package/runtime/agents/knowledge-infra-builder/knowledge/system.md +4 -0
  52. package/runtime/agents/knowledge-infra-builder/templates/.gitkeep +1 -0
  53. package/runtime/agents/knowledge-owner/AGENTS.md +7 -0
  54. package/runtime/agents/knowledge-owner/README.md +6 -0
  55. package/runtime/agents/knowledge-owner/agent.yaml +37 -0
  56. package/runtime/agents/knowledge-owner/capabilities/publish-knowledge-snapshot/capability.yaml +28 -0
  57. package/runtime/agents/knowledge-owner/capabilities/publish-knowledge-snapshot/decision-rules.md +6 -0
  58. package/runtime/agents/knowledge-owner/capabilities/publish-knowledge-snapshot/workflow.md +7 -0
  59. package/runtime/agents/knowledge-owner/infra/.gitkeep +1 -0
  60. package/runtime/agents/knowledge-owner/knowledge/context.md +4 -0
  61. package/runtime/agents/knowledge-owner/knowledge/system.md +4 -0
  62. package/runtime/agents/knowledge-owner/templates/.gitkeep +1 -0
  63. package/runtime/agents/knowledge-reviewer/AGENTS.md +7 -0
  64. package/runtime/agents/knowledge-reviewer/README.md +7 -0
  65. package/runtime/agents/knowledge-reviewer/agent.yaml +36 -0
  66. package/runtime/agents/knowledge-reviewer/capabilities/review-knowledge-snapshot/capability.yaml +26 -0
  67. package/runtime/agents/knowledge-reviewer/capabilities/review-knowledge-snapshot/decision-rules.md +6 -0
  68. package/runtime/agents/knowledge-reviewer/capabilities/review-knowledge-snapshot/workflow.md +7 -0
  69. package/runtime/agents/knowledge-reviewer/infra/.gitkeep +1 -0
  70. package/runtime/agents/knowledge-reviewer/knowledge/context.md +4 -0
  71. package/runtime/agents/knowledge-reviewer/knowledge/system.md +4 -0
  72. package/runtime/agents/knowledge-reviewer/templates/.gitkeep +1 -0
  73. package/runtime/agents/local-memory-manager/AGENTS.md +5 -0
  74. package/runtime/agents/local-memory-manager/README.md +7 -0
  75. package/runtime/agents/local-memory-manager/agent.yaml +38 -0
  76. package/runtime/agents/local-memory-manager/capabilities/curate-local-memory/capability.yaml +19 -0
  77. package/runtime/agents/local-memory-manager/capabilities/curate-local-memory/decision-rules.md +5 -0
  78. package/runtime/agents/local-memory-manager/capabilities/curate-local-memory/workflow.md +6 -0
  79. package/runtime/agents/local-memory-manager/capabilities/inspect-local-memory/capability.yaml +19 -0
  80. package/runtime/agents/local-memory-manager/capabilities/inspect-local-memory/decision-rules.md +5 -0
  81. package/runtime/agents/local-memory-manager/capabilities/inspect-local-memory/workflow.md +5 -0
  82. package/runtime/agents/local-memory-manager/infra/.gitkeep +1 -0
  83. package/runtime/agents/local-memory-manager/knowledge/context.md +4 -0
  84. package/runtime/agents/local-memory-manager/knowledge/system.md +4 -0
  85. package/runtime/agents/local-memory-manager/templates/.gitkeep +1 -0
  86. package/runtime/agents/memory-sync-manager/AGENTS.md +7 -0
  87. package/runtime/agents/memory-sync-manager/README.md +7 -0
  88. package/runtime/agents/memory-sync-manager/agent.yaml +37 -0
  89. package/runtime/agents/memory-sync-manager/capabilities/plan-memory-backup/capability.yaml +29 -0
  90. package/runtime/agents/memory-sync-manager/capabilities/plan-memory-backup/decision-rules.md +6 -0
  91. package/runtime/agents/memory-sync-manager/capabilities/plan-memory-backup/workflow.md +7 -0
  92. package/runtime/agents/memory-sync-manager/infra/.gitkeep +1 -0
  93. package/runtime/agents/memory-sync-manager/knowledge/context.md +4 -0
  94. package/runtime/agents/memory-sync-manager/knowledge/system.md +4 -0
  95. package/runtime/agents/memory-sync-manager/templates/.gitkeep +1 -0
  96. package/runtime/agents/shared-memory-curator/AGENTS.md +5 -0
  97. package/runtime/agents/shared-memory-curator/README.md +6 -0
  98. package/runtime/agents/shared-memory-curator/agent.yaml +38 -0
  99. package/runtime/agents/shared-memory-curator/capabilities/create-shared-memory/capability.yaml +19 -0
  100. package/runtime/agents/shared-memory-curator/capabilities/create-shared-memory/decision-rules.md +5 -0
  101. package/runtime/agents/shared-memory-curator/capabilities/create-shared-memory/workflow.md +5 -0
  102. package/runtime/agents/shared-memory-curator/capabilities/publish-shared-submission/capability.yaml +19 -0
  103. package/runtime/agents/shared-memory-curator/capabilities/publish-shared-submission/decision-rules.md +5 -0
  104. package/runtime/agents/shared-memory-curator/capabilities/publish-shared-submission/workflow.md +5 -0
  105. package/runtime/agents/shared-memory-curator/capabilities/review-shared-submission/capability.yaml +19 -0
  106. package/runtime/agents/shared-memory-curator/capabilities/review-shared-submission/decision-rules.md +5 -0
  107. package/runtime/agents/shared-memory-curator/capabilities/review-shared-submission/workflow.md +5 -0
  108. package/runtime/agents/shared-memory-curator/infra/.gitkeep +1 -0
  109. package/runtime/agents/shared-memory-curator/knowledge/context.md +5 -0
  110. package/runtime/agents/shared-memory-curator/knowledge/system.md +4 -0
  111. package/runtime/agents/shared-memory-curator/templates/.gitkeep +1 -0
  112. package/runtime/cli/README.md +35 -4
  113. package/runtime/cli/aikit/__init__.py +1 -1
  114. package/runtime/cli/aikit/agent_registry.py +4 -2
  115. package/runtime/cli/aikit/agentic_commands.py +158 -0
  116. package/runtime/cli/aikit/app_home.py +1 -0
  117. package/runtime/cli/aikit/audit.py +16 -6
  118. package/runtime/cli/aikit/catalog.py +278 -8
  119. package/runtime/cli/aikit/cli_dispatch.py +489 -13
  120. package/runtime/cli/aikit/cli_parser.py +145 -7
  121. package/runtime/cli/aikit/contribution.py +132 -2
  122. package/runtime/cli/aikit/doctor_runtime.py +85 -0
  123. package/runtime/cli/aikit/eval.py +356 -10
  124. package/runtime/cli/aikit/human_output.py +310 -4
  125. package/runtime/cli/aikit/interactive_wizard.py +148 -0
  126. package/runtime/cli/aikit/knowledge_base.py +1067 -0
  127. package/runtime/cli/aikit/llm.py +12 -4
  128. package/runtime/cli/aikit/local_artifacts.py +444 -0
  129. package/runtime/cli/aikit/local_llm.py +161 -0
  130. package/runtime/cli/aikit/main.py +15 -0
  131. package/runtime/cli/aikit/mcp_manifest.py +798 -0
  132. package/runtime/cli/aikit/mcp_tools.py +643 -5
  133. package/runtime/cli/aikit/memory.py +405 -0
  134. package/runtime/cli/aikit/mini_brain.py +20 -1
  135. package/runtime/cli/aikit/natural_prompt_runtime.py +125 -1
  136. package/runtime/cli/aikit/ollama.py +64 -15
  137. package/runtime/cli/aikit/onboarding.py +551 -0
  138. package/runtime/cli/aikit/output.py +67 -0
  139. package/runtime/cli/aikit/prompt_injection.py +12 -1
  140. package/runtime/cli/aikit/roadmap_cli.py +1 -1
  141. package/runtime/cli/aikit/secrets.py +3 -2
  142. package/runtime/cli/aikit/setup_wizard_payload.py +3 -0
  143. package/runtime/cli/aikit/shared_memory.py +415 -0
  144. package/runtime/cli/aikit/specialist_readiness.py +152 -0
  145. package/runtime/cli/aikit/tasks.py +104 -1
  146. package/runtime/cli/aikit/team.py +380 -0
  147. package/runtime/cli/aikit/toolchain.py +7 -2
  148. package/runtime/cli/aikit/workflows.py +115 -14
  149. package/runtime/providers/knowledge-github.yaml +40 -0
  150. package/runtime/providers/knowledge-google-drive.yaml +32 -0
  151. package/runtime/providers/knowledge-local.yaml +26 -0
  152. package/runtime/providers/knowledge-notion.yaml +32 -0
  153. package/runtime/providers/knowledge-obsidian.yaml +24 -0
  154. package/runtime/providers/knowledge-onedrive.yaml +36 -0
  155. package/runtime/providers/knowledge-s3.yaml +45 -0
  156. package/runtime/providers/knowledge-sharepoint.yaml +39 -0
  157. package/runtime/providers/knowledge-supabase.yaml +43 -0
  158. package/runtime/providers/knowledge-vector.yaml +39 -0
  159. package/runtime/requirements.txt +6 -0
  160. package/runtime/scripts/docker-cli-qa.sh +453 -0
  161. package/runtime/scripts/release-catalog-snapshot.json +55 -4
  162. package/runtime/scripts/release-gate.py +54 -13
  163. package/runtime/tooling/toolchain.yaml +92 -0
  164. package/runtime/vendor/skills/napkin/napkin.md +21 -7
  165. package/runtime/workflows/azure-card-analysis/README.md +3 -0
  166. package/runtime/workflows/azure-card-analysis/workflow.yaml +30 -0
  167. package/runtime/workflows/daily-pr-review/README.md +3 -0
  168. package/runtime/workflows/daily-pr-review/workflow.yaml +31 -0
  169. package/runtime/workflows/incident-analysis/README.md +3 -0
  170. package/runtime/workflows/incident-analysis/workflow.yaml +33 -0
  171. package/runtime/workflows/release-prep/README.md +3 -0
  172. package/runtime/workflows/release-prep/workflow.yaml +30 -0
@@ -25,12 +25,16 @@ def print_human(result: dict[str, Any]) -> None:
25
25
  print_doctor(result)
26
26
  elif kind == "commands":
27
27
  print_command_modes(result)
28
+ elif kind in {"onboarding", "onboarding-plan"}:
29
+ print_onboarding(result)
28
30
  elif kind == "architecture":
29
31
  print_architecture(result)
30
32
  elif kind == "roadmap":
31
33
  print_roadmap(result)
32
- elif kind in {"catalog", "catalog-item"}:
34
+ elif kind in {"catalog", "catalog-item", "catalog-index"}:
33
35
  print_catalog(result)
36
+ elif kind == "agentic-plan":
37
+ print_agentic_plan(result)
34
38
  elif kind == "route-explain":
35
39
  print_route_explain(result)
36
40
  elif kind in {"eval-suites", "eval-run", "eval-report"}:
@@ -39,9 +43,27 @@ def print_human(result: dict[str, Any]) -> None:
39
43
  print_secrets(result)
40
44
  elif kind in {"local-extensions", "local-extension", "local-extension-remove", "local-extension-validation"}:
41
45
  print_local_extensions(result)
46
+ elif kind in {
47
+ "local-skills",
48
+ "local-skill",
49
+ "local-scripts",
50
+ "local-script",
51
+ "local-script-run",
52
+ "local-agents",
53
+ "local-agent",
54
+ "local-agent-validation",
55
+ "local-automations",
56
+ "local-automation",
57
+ "local-automation-validation",
58
+ }:
59
+ print_local_artifacts(result)
42
60
  elif kind in {"workflows", "workflow", "workflow-install", "workflow-run"}:
43
61
  print_workflows(result)
44
- elif kind in {"contributions", "contribution-checklist", "contribution-validation", "contribution-prepare", "contribution-review"}:
62
+ elif kind in {"team", "team-doctor", "team-onboarding", "team-profiles", "team-profile", "team-profile-export", "team-profile-import"}:
63
+ print_team(result)
64
+ elif kind in {"knowledge", "knowledge-doctor", "knowledge-search", "knowledge-index", "knowledge-snapshot", "knowledge-review", "knowledge-publish", "knowledge-base", "knowledge-base-tokens", "knowledge-base-token"}:
65
+ print_knowledge(result)
66
+ elif kind in {"contributions", "contribution-checklist", "contribution-validation", "contribution-prepare", "contribution-review", "contribution-pr"}:
45
67
  print_contribution(result)
46
68
  elif kind == "agent":
47
69
  print_agent_response(result)
@@ -77,8 +99,12 @@ def print_human(result: dict[str, Any]) -> None:
77
99
  print_source_remove(result)
78
100
  elif kind in {"wizards", "wizard"}:
79
101
  print_wizard(result)
102
+ elif kind in {"shared-memory", "shared-memories", "shared-memory-read", "shared-memory-submission", "shared-memory-review", "shared-memory-publish"}:
103
+ print_shared_memory(result)
80
104
  elif kind == "memory":
81
105
  print_memory(result)
106
+ elif kind in {"memory-backup", "memory-backups", "memory-backup-restore", "memory-backup-delete"}:
107
+ print_memory_backup(result)
82
108
  elif kind == "memory-path":
83
109
  print_memory_path(result)
84
110
  elif kind == "memory-reset":
@@ -93,7 +119,7 @@ def print_human(result: dict[str, Any]) -> None:
93
119
  print_sessions(result)
94
120
  elif kind == "session":
95
121
  print_session(result)
96
- elif kind == "setup":
122
+ elif kind in {"setup", "mini-brain-setup"}:
97
123
  print_setup(result)
98
124
  elif kind == "toolchain":
99
125
  print_toolchain(result)
@@ -131,6 +157,8 @@ def print_human(result: dict[str, Any]) -> None:
131
157
  print_control(result)
132
158
  elif kind in {"ollama-status", "ollama-models", "ollama-pull", "ollama-update"}:
133
159
  print_ollama(result)
160
+ elif kind in {"local-llm", "local-llm-doctor", "local-llm-models", "local-llm-install", "local-llm-remove", "local-llm-benchmark"}:
161
+ print_local_llm(result)
134
162
  elif kind in {"mcp-manifest", "mcp-tools", "mcp-doctor"}:
135
163
  print_mcp(result)
136
164
  elif kind == "install":
@@ -162,6 +190,10 @@ def print_roadmap(result: dict[str, Any]) -> None:
162
190
 
163
191
 
164
192
  def print_catalog(result: dict[str, Any]) -> None:
193
+ if result["kind"] == "catalog-index":
194
+ print(f"Catalog index {result.get('status')}: {result.get('count', 0)} item(s)")
195
+ print(f"Path: {result.get('path')}")
196
+ return
165
197
  if result["kind"] == "catalog-item":
166
198
  item = result["item"]
167
199
  print(f"{item.get('type')} {item.get('id')}")
@@ -186,6 +218,19 @@ def print_route_explain(result: dict[str, Any]) -> None:
186
218
  print(f"Next: {result['next_step']}")
187
219
 
188
220
 
221
+ def print_agentic_plan(result: dict[str, Any]) -> None:
222
+ summary = result.get("summary") if isinstance(result.get("summary"), dict) else {}
223
+ print(f"Agentic plan: {result.get('status')}")
224
+ print(f"Routing: {summary.get('routing_status') or '-'}")
225
+ print(f"Selected: {summary.get('selected_agent_id') or '-'} / {summary.get('selected_capability_id') or '-'}")
226
+ print(f"Model: {summary.get('model_strategy') or '-'}")
227
+ print(f"Tasks: {summary.get('specialist_tasks', 0)} specialist, {summary.get('configuration_tasks', 0)} configuration")
228
+ if summary.get("review_required"):
229
+ print("Review: required")
230
+ if summary.get("needs_input"):
231
+ print("Next: provide the missing configuration, route confirmation, or model permission.")
232
+
233
+
189
234
  def print_eval(result: dict[str, Any]) -> None:
190
235
  if result["kind"] == "eval-suites":
191
236
  print("Eval suites:")
@@ -216,6 +261,42 @@ def print_local_extensions(result: dict[str, Any]) -> None:
216
261
  print(f"- {item.get('id')} {state} {item.get('path')}")
217
262
 
218
263
 
264
+ def print_local_artifacts(result: dict[str, Any]) -> None:
265
+ kind = result.get("kind")
266
+ print(f"{kind}: {result.get('status')}")
267
+ if "items" in result:
268
+ for item in result.get("items") or []:
269
+ state = "enabled" if item.get("enabled") else "disabled"
270
+ schedule = item.get("schedule") if isinstance(item.get("schedule"), dict) else {}
271
+ schedule_label = schedule.get("type") or ""
272
+ if schedule.get("every"):
273
+ schedule_label = f"{schedule_label}:{schedule.get('every')}"
274
+ if schedule.get("cron"):
275
+ schedule_label = f"{schedule_label}:{schedule.get('cron')}"
276
+ suffix = f" [{schedule_label}]" if schedule_label else ""
277
+ title = f" - {item.get('title')}" if item.get("title") else ""
278
+ print(f"- {item.get('id')} {state}{suffix}{title} {item.get('path')}")
279
+ if not result.get("items"):
280
+ print("- none")
281
+ return
282
+ automation = result.get("automation") if isinstance(result.get("automation"), dict) else None
283
+ if automation:
284
+ print(f"Automation: {automation.get('id')}")
285
+ print(f"Title: {automation.get('title') or '-'}")
286
+ schedule = automation.get("schedule") if isinstance(automation.get("schedule"), dict) else {}
287
+ print(f"Schedule: {schedule.get('type') or 'manual'}")
288
+ print(f"Enabled: {'yes' if automation.get('enabled') is not False else 'no'}")
289
+ if result.get("id"):
290
+ print(f"Id: {result.get('id')}")
291
+ if result.get("path"):
292
+ print(f"Path: {result.get('path')}")
293
+ if result.get("checks"):
294
+ for check in result.get("checks") or []:
295
+ print(f"- {check.get('id')}: {check.get('status')}")
296
+ if result.get("message"):
297
+ print(result["message"])
298
+
299
+
219
300
  def print_workflows(result: dict[str, Any]) -> None:
220
301
  print(f"{result['kind']}: {result.get('status')}")
221
302
  for item in result.get("items") or []:
@@ -225,6 +306,46 @@ def print_workflows(result: dict[str, Any]) -> None:
225
306
  print(f"{workflow.get('id')}: {workflow.get('description')}")
226
307
 
227
308
 
309
+ def print_team(result: dict[str, Any]) -> None:
310
+ print(f"{result['kind']}: {result.get('status')}")
311
+ if result.get("path"):
312
+ print(f"Path: {result.get('path')}")
313
+ if result.get("active_profile"):
314
+ print(f"Active: {result.get('active_profile')}")
315
+ if result.get("profiles"):
316
+ print(f"Profiles: {', '.join(str(item) for item in result.get('profiles') or [])}")
317
+ if result.get("items"):
318
+ for item in result.get("items") or []:
319
+ print(f"- {item.get('id')}: {item.get('description') or '-'}")
320
+ if result.get("profile"):
321
+ profile = result["profile"]
322
+ print(f"Profile: {profile.get('id')}")
323
+ print(f"Workflows: {', '.join(str(item) for item in profile.get('workflows') or []) or '-'}")
324
+ for check in result.get("checks") or []:
325
+ print(f"- {check.get('id')}: {check.get('status')}")
326
+ for step in result.get("next_steps") or []:
327
+ print(f"Next: {step}")
328
+
329
+
330
+ def print_knowledge(result: dict[str, Any]) -> None:
331
+ print(f"{result['kind']}: {result.get('status')}")
332
+ if result.get("path"):
333
+ print(f"Path: {result.get('path')}")
334
+ if result.get("snapshot_id"):
335
+ print(f"Snapshot: {result.get('snapshot_id')}")
336
+ if result.get("count") is not None:
337
+ print(f"Count: {result.get('count')}")
338
+ for item in result.get("items") or []:
339
+ suffix = f" ({item.get('score')})" if item.get("score") is not None else ""
340
+ print(f"- {item.get('path')}{suffix}")
341
+ for check in result.get("checks") or []:
342
+ print(f"- {check.get('id')}: {check.get('status')}")
343
+ for finding in result.get("findings") or []:
344
+ print(f"Finding: {finding.get('reason')} {finding.get('path') or ''}".rstrip())
345
+ for step in result.get("next_steps") or []:
346
+ print(f"Next: {step}")
347
+
348
+
228
349
  def print_contribution(result: dict[str, Any]) -> None:
229
350
  print(f"{result['kind']}: {result.get('status')}")
230
351
  for check in result.get("checks") or []:
@@ -352,6 +473,13 @@ def print_doctor(result: dict[str, Any]) -> None:
352
473
  print(f"- Plugins: {plugins.get('status', '-')}")
353
474
  print(f"- Providers: {providers.get('status', '-')} ({providers.get('ok', 0)} ok, {providers.get('missing', 0)} missing)")
354
475
  print(f"- LLM: {llm.get('status', '-')} ({llm.get('ok', 0)} ok, {llm.get('missing', 0)} missing)")
476
+ operational = result.get("operational") or {}
477
+ if operational:
478
+ print("\nOperational:")
479
+ for key, value in operational.items():
480
+ if isinstance(value, dict):
481
+ suffix = f" ({value.get('count')})" if value.get("count") is not None else ""
482
+ print(f"- {key}: {value.get('status', '-')}{suffix}")
355
483
  if result["warnings"]:
356
484
  print("\nWarnings:")
357
485
  for warning in result["warnings"]:
@@ -371,6 +499,98 @@ def print_command_modes(result: dict[str, Any]) -> None:
371
499
  print(f"- {item['command']}")
372
500
 
373
501
 
502
+ def print_onboarding(result: dict[str, Any]) -> None:
503
+ if result.get("kind") == "onboarding-plan":
504
+ print_onboarding_plan(result)
505
+ return
506
+ agent = result.get("agent") or {}
507
+ print(f"{agent.get('name') or 'Agent DevKit'}")
508
+ print(f"Status: {result.get('status')}")
509
+
510
+ home = result.get("home") or {}
511
+ print(f"Home: {home.get('home')}")
512
+
513
+ memory = result.get("memory") or {}
514
+ created = memory.get("created") or []
515
+ memory_suffix = f" ({len(created)} file(s) created)" if created else ""
516
+ print(f"Memoria local: {memory.get('status')}{memory_suffix}")
517
+
518
+ sessions = result.get("sessions") or {}
519
+ active = sessions.get("active_session_id") or "-"
520
+ print(f"Sessao ativa: {active} ({sessions.get('count', 0)} total)")
521
+
522
+ llm = result.get("llm") or {}
523
+ print(f"LLMs: {llm.get('usable_count', 0)} usable / {llm.get('configured_count', 0)} configured")
524
+
525
+ ollama = result.get("ollama") or {}
526
+ print(f"Ollama: {ollama.get('status')} ({ollama.get('model_count', 0)} model(s))")
527
+
528
+ toolchain = result.get("toolchain") or {}
529
+ print(
530
+ "Toolchain: "
531
+ f"{toolchain.get('status')} "
532
+ f"({toolchain.get('ok_count', 0)} ok, {toolchain.get('missing_count', 0)} missing)"
533
+ )
534
+
535
+ sources = result.get("sources") or {}
536
+ tasks = result.get("tasks") or {}
537
+ specialists = result.get("specialists") or {}
538
+ print(f"Sources: {sources.get('count', 0)} configured")
539
+ if specialists:
540
+ missing = specialists.get("missing_providers") or []
541
+ missing_label = ""
542
+ if missing:
543
+ first_missing = missing[0] if isinstance(missing[0], dict) else {}
544
+ if first_missing.get("id"):
545
+ missing_label = f", first missing: {first_missing['id']}"
546
+ print(
547
+ "Especialistas: "
548
+ f"{specialists.get('ready_agents', 0)} ready / "
549
+ f"{specialists.get('agents_with_provider_requirements', 0)} provider-bound"
550
+ f"{missing_label}"
551
+ )
552
+ print(f"Tasks: {tasks.get('enabled_count', 0)} enabled / {tasks.get('count', 0)} total")
553
+ if tasks.get("due_count"):
554
+ print(f"Due tasks: {tasks.get('due_count')}")
555
+
556
+ if result.get("assistant_prompt"):
557
+ print(f"\n{result['assistant_prompt']}")
558
+
559
+ blockers = result.get("blockers") or []
560
+ if blockers:
561
+ print("\nNeeds setup:")
562
+ for blocker in blockers:
563
+ print(f"- {blocker.get('message')}")
564
+ if blocker.get("command"):
565
+ print(f" {blocker['command']}")
566
+
567
+ actions = result.get("suggested_actions") or []
568
+ if actions:
569
+ print("\nNext:")
570
+ for action in actions[:8]:
571
+ label = action.get("label") or action.get("id")
572
+ command = action.get("command")
573
+ print(f"- {label}: {command}")
574
+
575
+ modes = result.get("onboarding_modes") or []
576
+ if modes:
577
+ print("\nOnboarding:")
578
+ for mode in modes:
579
+ print(f"- {mode.get('label')}: {mode.get('command')}")
580
+
581
+
582
+ def print_onboarding_plan(result: dict[str, Any]) -> None:
583
+ print(f"Onboarding {result.get('mode')}: {result.get('status')}")
584
+ print("External actions executed: no")
585
+ catalog = result.get("agent_catalog") or {}
586
+ print(f"Catalog: {catalog.get('agents', 0)} agents / {catalog.get('capabilities', 0)} capabilities")
587
+ steps = result.get("steps") or []
588
+ if steps:
589
+ print("\nSteps:")
590
+ for step in steps:
591
+ print(f"- {step.get('id')}: {step.get('command')}")
592
+
593
+
374
594
  def print_architecture(result: dict[str, Any]) -> None:
375
595
  principal = result.get("principal_agent") or {}
376
596
  print(f"{principal.get('name', 'Agent DevKit')}: {principal.get('role', 'runtime-agent')}")
@@ -535,6 +755,52 @@ def print_memory_path(result: dict[str, Any]) -> None:
535
755
  print(f"- {item['name']}: {item['path']}")
536
756
 
537
757
 
758
+ def print_memory_backup(result: dict[str, Any]) -> None:
759
+ print(f"Memory backup: {result.get('status')}")
760
+ if result.get("home"):
761
+ print(f"Home: {result.get('home')}")
762
+ backup = result.get("backup") if isinstance(result.get("backup"), dict) else {}
763
+ if backup:
764
+ print(f"ID: {backup.get('id')}")
765
+ print(f"Path: {backup.get('path')}")
766
+ print(f"Files: {backup.get('file_count', 0)}")
767
+ print(f"Remote upload: {'yes' if backup.get('remote_upload') else 'no'}")
768
+ print(f"Encrypted: {'yes' if backup.get('encrypted') else 'no'}")
769
+ if result.get("items"):
770
+ for item in result["items"]:
771
+ print(f"- {item.get('id')}: {item.get('file_count', 0)} file(s)")
772
+ if result.get("next_steps"):
773
+ print("Next steps:")
774
+ for step in result["next_steps"]:
775
+ print(f"- {step}")
776
+
777
+
778
+ def print_shared_memory(result: dict[str, Any]) -> None:
779
+ print(f"Shared memory: {result.get('status')}")
780
+ memory = result.get("memory") if isinstance(result.get("memory"), dict) else {}
781
+ if memory:
782
+ print(f"ID: {memory.get('id')}")
783
+ print(f"URL: {memory.get('share_url')}")
784
+ if result.get("submission_id"):
785
+ print(f"Submission: {result.get('submission_id')}")
786
+ if result.get("path"):
787
+ print(f"Path: {result.get('path')}")
788
+ if result.get("content"):
789
+ print(result["content"])
790
+ if result.get("items"):
791
+ for item in result["items"]:
792
+ print(f"- {item.get('id')}: {item.get('title')}")
793
+ access = result.get("contributor_access") if isinstance(result.get("contributor_access"), dict) else {}
794
+ if access:
795
+ print("Contributor access:")
796
+ print(f"- URL: {access.get('url')}")
797
+ print(f"- Key: {access.get('key')}")
798
+ owner_access = result.get("owner_access") if isinstance(result.get("owner_access"), dict) else {}
799
+ if owner_access:
800
+ print("Owner access:")
801
+ print(f"- Key: {owner_access.get('key')}")
802
+
803
+
538
804
  def print_personality(result: dict[str, Any]) -> None:
539
805
  print(f"Personality: {result.get('status', 'ok')}")
540
806
  print(f"Path: {result['path']}")
@@ -545,7 +811,7 @@ def print_personality(result: dict[str, Any]) -> None:
545
811
  print(f"Detail level: {result.get('detail_level') or '-'}")
546
812
  if result.get("message"):
547
813
  print(result["message"])
548
- if result.get("questions"):
814
+ if result.get("status") == "needs-input" and result.get("questions"):
549
815
  print("Setup questions:")
550
816
  for question in result["questions"]:
551
817
  print(f"- {question}")
@@ -992,6 +1258,46 @@ def print_ollama(result: dict[str, Any]) -> None:
992
1258
  print(result["message"])
993
1259
 
994
1260
 
1261
+ def print_local_llm(result: dict[str, Any]) -> None:
1262
+ kind = result.get("kind")
1263
+ print(f"Local LLM: {result.get('status')}")
1264
+ if kind == "local-llm":
1265
+ mini = result.get("mini_brain") or {}
1266
+ print(f"Mini-brain: {mini.get('status')} enabled={mini.get('enabled')}")
1267
+ print(f"Workers: {len(result.get('workers') or [])}")
1268
+ return
1269
+ if kind == "local-llm-doctor":
1270
+ ollama = result.get("ollama") or {}
1271
+ mini = result.get("mini_brain") or {}
1272
+ print(f"Ollama: {ollama.get('status')}")
1273
+ print(f"Mini-brain: {mini.get('status')} enabled={mini.get('enabled')}")
1274
+ for step in result.get("next_steps") or []:
1275
+ print(f"- {step}")
1276
+ return
1277
+ if kind == "local-llm-models":
1278
+ print(f"Binary: {result.get('binary') or '-'}")
1279
+ for item in result.get("items") or []:
1280
+ print(f"- {item.get('name')} {item.get('size') or '-'}")
1281
+ recommended = [item for item in result.get("recommended") or [] if not item.get("installed")]
1282
+ if recommended:
1283
+ print("Recommended:")
1284
+ for item in recommended[:5]:
1285
+ print(f"- {item.get('name')}: {item.get('recommended_for')}")
1286
+ return
1287
+ if kind == "local-llm-benchmark":
1288
+ print(f"Model: {result.get('model')}")
1289
+ for check in result.get("checks") or []:
1290
+ print(f"- {check.get('id')}: {check.get('status')}")
1291
+ for step in result.get("next_steps") or []:
1292
+ print(f"Next: {step}")
1293
+ return
1294
+ if result.get("command"):
1295
+ command = result["command"]
1296
+ print("Command: " + (" ".join(command) if isinstance(command, list) else str(command)))
1297
+ if result.get("message"):
1298
+ print(result["message"])
1299
+
1300
+
995
1301
  def print_mcp(result: dict[str, Any]) -> None:
996
1302
  print(f"MCP: {result.get('status', 'ok')}")
997
1303
  print(f"Transport: {result.get('transport', '-')}")
@@ -7,12 +7,24 @@ from typing import Any
7
7
 
8
8
  from cli.aikit.core.requests import AgentPromptRequest
9
9
  from cli.aikit.core.runtime import run_agent_prompt
10
+ from cli.aikit.llm import BACKENDS, configure_backend
11
+ from cli.aikit.mini_brain import DEFAULT_OLLAMA_MODEL, setup_mini_brain
12
+ from cli.aikit.ollama import ollama_status
13
+ from cli.aikit.onboarding import onboarding_status
14
+ from cli.aikit.personality import load_personality, update_personality
15
+ from cli.aikit.runtime_paths import ROOT
10
16
  from cli.aikit.wizard_state import WizardStateError, answer_wizard, cancel_wizard, show_wizard
11
17
 
12
18
 
13
19
  def maybe_run_interactive_wizard(result: dict[str, Any]) -> dict[str, Any]:
14
20
  if not sys.stdin.isatty() or not sys.stdout.isatty():
15
21
  return result
22
+ if result.get("kind") == "onboarding" and result.get("status") != "ready":
23
+ return run_interactive_onboarding(result)
24
+ if result.get("kind") == "personality" and result.get("status") == "needs-input":
25
+ print(result.get("message") or "Vou configurar nome, usuario e estilo local.")
26
+ configure_personality_interactively(result)
27
+ return load_personality()
16
28
  wizard = result.get("setup_wizard") if isinstance(result.get("setup_wizard"), dict) else None
17
29
  if not wizard or not wizard.get("wizard_id") or result.get("status") != "needs-input":
18
30
  return result
@@ -68,6 +80,142 @@ def print_interactive_question(question: dict[str, Any]) -> None:
68
80
  print("Digite 'cancelar' para interromper.")
69
81
 
70
82
 
83
+ def run_interactive_onboarding(result: dict[str, Any]) -> dict[str, Any]:
84
+ agent = result.get("agent") if isinstance(result.get("agent"), dict) else {}
85
+ print(f"{agent.get('name') or 'Agent DevKit'} iniciado.")
86
+ print("Vou revisar o estado local e pedir apenas o que for necessario.")
87
+ mode = choose_onboarding_mode()
88
+ if mode == "skip":
89
+ print("Onboarding pulado por agora.")
90
+ return result
91
+ if ask_yes_no("Deseja configurar nome, usuario e estilo agora?", default=True):
92
+ configure_personality_interactively(agent)
93
+
94
+ fresh = onboarding_status(ROOT)
95
+ llm = fresh.get("llm") if isinstance(fresh.get("llm"), dict) else {}
96
+ if int(llm.get("usable_count") or 0) < 1:
97
+ configure_llm_interactively()
98
+
99
+ fresh = onboarding_status(ROOT)
100
+ ollama = fresh.get("ollama") if isinstance(fresh.get("ollama"), dict) else {}
101
+ if ollama.get("status") == "missing":
102
+ install_plan = ollama.get("install_plan") if isinstance(ollama.get("install_plan"), dict) else {}
103
+ command = install_plan.get("command")
104
+ print("\nOllama nao foi encontrado.")
105
+ if command:
106
+ print(f"Instalacao sugerida: {command}")
107
+ print("Depois de instalar, rode `agent setup mini-brain --yes` para baixar o Qwen3-0.6B.")
108
+ elif ask_yes_no(f"Deseja habilitar o mini cerebro local com {DEFAULT_OLLAMA_MODEL}?", default=False):
109
+ set_default = ask_yes_no("Usar este mini cerebro como backend LLM padrao?", default=False)
110
+ setup = setup_mini_brain(yes=True, set_default=set_default)
111
+ print(setup.get("message") or f"Mini cerebro: {setup.get('status')}")
112
+
113
+ fresh = onboarding_status(ROOT)
114
+ toolchain = fresh.get("toolchain") if isinstance(fresh.get("toolchain"), dict) else {}
115
+ optional_missing = toolchain.get("optional_missing") or []
116
+ if optional_missing:
117
+ print("\nFerramentas opcionais ausentes: " + ", ".join(str(item) for item in optional_missing))
118
+ print("Para revisar instalacoes com opt-in: agent toolchain doctor")
119
+ if mode == "complete" and ask_yes_no("Deseja abrir o plano de toolchain agora?", default=False):
120
+ print("Rode: agent toolchain install all --dry-run")
121
+ if mode == "complete":
122
+ print("\nOnboarding completo tambem pode revisar sources, notificacoes, knowledge e memoria compartilhada sob demanda:")
123
+ print("- agent source list")
124
+ print("- agent notifications doctor")
125
+ print("- agent knowledge doctor")
126
+ print("- agent shared-memory list")
127
+ return onboarding_status(ROOT)
128
+
129
+
130
+ def choose_onboarding_mode() -> str:
131
+ print("\nModos de onboarding:")
132
+ print("1. minimo: identidade, coordenador LLM, mini-cerebro local e memoria")
133
+ print("2. completo: minimo + toolchain, sources, notificacoes, knowledge e memorias")
134
+ print("3. pular")
135
+ answer = ask_text("Escolha o modo", default="minimo").strip().lower()
136
+ if answer in {"1", "minimo", "mínimo", "minimal"}:
137
+ return "minimal"
138
+ if answer in {"2", "completo", "complete", "full"}:
139
+ return "complete"
140
+ if answer in {"3", "pular", "skip", "cancelar", "cancel"}:
141
+ return "skip"
142
+ return "minimal"
143
+
144
+
145
+ def configure_personality_interactively(agent: dict[str, Any]) -> None:
146
+ current_name = str(agent.get("name") or "Agent DevKit")
147
+ current_tone = str(agent.get("tone") or "direct")
148
+ current_detail = str(agent.get("detail_level") or "concise")
149
+ agent_name = ask_text("Como devo me chamar?", default=current_name)
150
+ user_name = ask_text("Como voce se chama?", default=str(agent.get("user_name") or ""))
151
+ language = ask_text("Idioma padrao das respostas?", default=str(agent.get("language") or "pt-BR"))
152
+ tone = ask_text("Tom das respostas?", default=current_tone)
153
+ detail_level = ask_text("Nivel de detalhe?", default=current_detail)
154
+ update_personality(
155
+ agent_name=agent_name,
156
+ user_name=user_name,
157
+ language=language,
158
+ tone=tone,
159
+ detail_level=detail_level,
160
+ )
161
+
162
+
163
+ def configure_llm_interactively() -> None:
164
+ print("\nNenhum backend LLM coordenador utilizavel foi detectado.")
165
+ print("Opcoes: claude-code, codex-cli, ollama, openai, anthropic, openrouter, pular")
166
+ choice = ask_text("Qual backend deseja configurar primeiro?", default="pular").strip().lower()
167
+ if choice in {"", "pular", "skip", "cancelar", "cancel"}:
168
+ print("Configuracao de LLM pulada por agora.")
169
+ return
170
+ if choice not in BACKENDS:
171
+ print(f"Backend desconhecido: {choice}")
172
+ return
173
+ if choice in {"claude-code", "codex-cli"}:
174
+ configure_backend(choice, set_default=True)
175
+ print(f"{choice} registrado como backend padrao. A autenticacao continua no CLI oficial.")
176
+ return
177
+ if choice == "ollama":
178
+ status = ollama_status()
179
+ if status.get("status") != "ok":
180
+ install_plan = status.get("install_plan") if isinstance(status.get("install_plan"), dict) else {}
181
+ print("Ollama ainda nao esta instalado.")
182
+ if install_plan.get("command"):
183
+ print(f"Instalacao sugerida: {install_plan['command']}")
184
+ return
185
+ configure_backend("ollama", model=DEFAULT_OLLAMA_MODEL, set_default=True)
186
+ print("Ollama registrado como backend padrao.")
187
+ return
188
+ env_default = BACKENDS[choice].api_key_env or ""
189
+ api_key_env = ask_text("Nome da variavel de ambiente da API key?", default=env_default)
190
+ model = ask_text("Modelo padrao?", default=BACKENDS[choice].default_model or "")
191
+ configure_backend(choice, api_key_env=api_key_env, model=model, set_default=True)
192
+ print(f"{choice} registrado sem armazenar segredo; a chave deve existir em ${api_key_env}.")
193
+
194
+
195
+ def ask_yes_no(question: str, *, default: bool) -> bool:
196
+ suffix = "[S/n]" if default else "[s/N]"
197
+ answer = ask_text(f"{question} {suffix}", default="sim" if default else "nao").strip().lower()
198
+ if answer in {"s", "sim", "y", "yes", "true", "1", "ok"}:
199
+ return True
200
+ if answer in {"n", "nao", "não", "no", "false", "0"}:
201
+ return False
202
+ return default
203
+
204
+
205
+ def ask_text(question: str, *, default: str = "") -> str:
206
+ prompt = f"{question}"
207
+ if default:
208
+ prompt += f" ({default})"
209
+ prompt += "\n> "
210
+ try:
211
+ answer = input(prompt)
212
+ except (EOFError, KeyboardInterrupt):
213
+ print()
214
+ return default
215
+ value = " ".join(answer.split())
216
+ return value or default
217
+
218
+
71
219
  def resume_agent_prompt(prompt: str) -> dict[str, Any]:
72
220
  result = run_agent_prompt(
73
221
  AgentPromptRequest(