@openlife/cli 1.7.3

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 (394) hide show
  1. package/INSTALL.md +266 -0
  2. package/LICENSE +21 -0
  3. package/README.md +142 -0
  4. package/bin/openlife.js +3 -0
  5. package/dist/admin_panel_server.js +66 -0
  6. package/dist/cli/AgentManager.js +109 -0
  7. package/dist/cli/AutonomousInstaller.js +134 -0
  8. package/dist/cli/DreamOrganizer.js +88 -0
  9. package/dist/cli/HostInstaller.js +426 -0
  10. package/dist/cli/InstallBanner.js +16 -0
  11. package/dist/cli/InstallFlow.js +256 -0
  12. package/dist/cli/InstallHeadless.js +47 -0
  13. package/dist/cli/InstallModules.js +148 -0
  14. package/dist/cli/InstallStateStore.js +75 -0
  15. package/dist/cli/InstallWizard.js +364 -0
  16. package/dist/cli/ProfileManager.js +163 -0
  17. package/dist/cli/SystemInstaller.js +89 -0
  18. package/dist/cli/WorldClassCommands.js +208 -0
  19. package/dist/design/DesignMdImporter.js +82 -0
  20. package/dist/design/DesignMdMode.js +93 -0
  21. package/dist/design/DesignMdRegistry.js +67 -0
  22. package/dist/index.js +2575 -0
  23. package/dist/memory/ConversationMemory.js +33 -0
  24. package/dist/memory/LocalMemoryProvider.js +86 -0
  25. package/dist/memory/Mem0Provider.js +16 -0
  26. package/dist/memory/MemoryNamespacePolicy.js +27 -0
  27. package/dist/memory/MemoryOrchestrator.js +65 -0
  28. package/dist/memory/MemoryPromotionFlow.js +32 -0
  29. package/dist/memory/MemoryProvider.js +2 -0
  30. package/dist/memory/MemoryProviderRegistry.js +27 -0
  31. package/dist/memory/MemoryRetentionPolicy.js +60 -0
  32. package/dist/memory/MempalaceProvider.js +72 -0
  33. package/dist/memory/OmniMemory.js +106 -0
  34. package/dist/memory/RedisAgentMemoryProvider.js +16 -0
  35. package/dist/memory/SessionManager.js +86 -0
  36. package/dist/memory/ZepGraphitiProvider.js +16 -0
  37. package/dist/orchestrator/AgentRegistry.js +56 -0
  38. package/dist/orchestrator/AgentScoring.js +82 -0
  39. package/dist/orchestrator/AgentTeam.js +22 -0
  40. package/dist/orchestrator/ArbitrationAgent.js +43 -0
  41. package/dist/orchestrator/ArbitrationScorecard.js +17 -0
  42. package/dist/orchestrator/AssetPromotionEngine.js +65 -0
  43. package/dist/orchestrator/AssetReuseRouter.js +63 -0
  44. package/dist/orchestrator/BenchmarkEngine.js +75 -0
  45. package/dist/orchestrator/Brain.js +298 -0
  46. package/dist/orchestrator/CadenceEngine.js +76 -0
  47. package/dist/orchestrator/CapabilityRouter.js +36 -0
  48. package/dist/orchestrator/CommandLanguage.js +27 -0
  49. package/dist/orchestrator/CommandRouter.js +70 -0
  50. package/dist/orchestrator/ConsequenceForecaster.js +286 -0
  51. package/dist/orchestrator/CronManager.js +286 -0
  52. package/dist/orchestrator/DynamicAgentBuilder.js +48 -0
  53. package/dist/orchestrator/DynamicAgentExecutor.js +15 -0
  54. package/dist/orchestrator/EnterpriseAgenticCore.js +276 -0
  55. package/dist/orchestrator/ExecutionBoard.js +86 -0
  56. package/dist/orchestrator/ExecutionIntent.js +13 -0
  57. package/dist/orchestrator/ExecutionModePolicy.js +48 -0
  58. package/dist/orchestrator/ExecutionRouter.js +9 -0
  59. package/dist/orchestrator/ExecutionState.js +20 -0
  60. package/dist/orchestrator/ExecutorHealth.js +86 -0
  61. package/dist/orchestrator/ExternalCatalogRegistry.js +83 -0
  62. package/dist/orchestrator/Gatekeeper.js +414 -0
  63. package/dist/orchestrator/Gateway.js +508 -0
  64. package/dist/orchestrator/GovernanceConsentStore.js +66 -0
  65. package/dist/orchestrator/GovernanceLayer.js +179 -0
  66. package/dist/orchestrator/GovernancePolicyStore.js +53 -0
  67. package/dist/orchestrator/GovernanceScopeLedger.js +134 -0
  68. package/dist/orchestrator/GovernanceScopePolicy.js +67 -0
  69. package/dist/orchestrator/IntentClassifier.js +45 -0
  70. package/dist/orchestrator/JobLifecycle.js +91 -0
  71. package/dist/orchestrator/LearningRouter.js +24 -0
  72. package/dist/orchestrator/MediaManager.js +92 -0
  73. package/dist/orchestrator/MemoryCuratorAgent.js +41 -0
  74. package/dist/orchestrator/MissionState.js +155 -0
  75. package/dist/orchestrator/ModelManager.js +84 -0
  76. package/dist/orchestrator/OperatingSystem.js +71 -0
  77. package/dist/orchestrator/OperationalMemoryStore.js +94 -0
  78. package/dist/orchestrator/OptimizationLoop.js +72 -0
  79. package/dist/orchestrator/OrchestrationLoop.js +905 -0
  80. package/dist/orchestrator/OrgStructure.js +88 -0
  81. package/dist/orchestrator/OutcomeSimulator.js +46 -0
  82. package/dist/orchestrator/ParallelOrchestrationLoop.js +36 -0
  83. package/dist/orchestrator/PerformanceScorecard.js +105 -0
  84. package/dist/orchestrator/PlannerAgent.js +46 -0
  85. package/dist/orchestrator/ProcessSandbox.js +129 -0
  86. package/dist/orchestrator/PromotionPipeline.js +74 -0
  87. package/dist/orchestrator/PromotionReviewGate.js +11 -0
  88. package/dist/orchestrator/QueueScheduler.js +260 -0
  89. package/dist/orchestrator/ReleaseGate.js +36 -0
  90. package/dist/orchestrator/ReleaseWorkflow.js +68 -0
  91. package/dist/orchestrator/RemotePublisher.js +139 -0
  92. package/dist/orchestrator/ReuseEngine.js +89 -0
  93. package/dist/orchestrator/ReviewerAgent.js +49 -0
  94. package/dist/orchestrator/RoleHandoff.js +65 -0
  95. package/dist/orchestrator/RuntimeHealthMonitor.js +143 -0
  96. package/dist/orchestrator/RuntimePolicy.js +105 -0
  97. package/dist/orchestrator/RuntimeProbe.js +97 -0
  98. package/dist/orchestrator/RuntimeRegistry.js +73 -0
  99. package/dist/orchestrator/SandboxPolicy.js +22 -0
  100. package/dist/orchestrator/SecurityDownloadGuard.js +169 -0
  101. package/dist/orchestrator/SecurityEventStore.js +58 -0
  102. package/dist/orchestrator/ServiceCompletionPolicy.js +36 -0
  103. package/dist/orchestrator/ServiceState.js +195 -0
  104. package/dist/orchestrator/SkillCreator.js +404 -0
  105. package/dist/orchestrator/SkillLearningLoop.js +57 -0
  106. package/dist/orchestrator/SkillManager.js +75 -0
  107. package/dist/orchestrator/SkillNetwork.js +29 -0
  108. package/dist/orchestrator/SkillRegistryV2.js +28 -0
  109. package/dist/orchestrator/SkillScoring.js +70 -0
  110. package/dist/orchestrator/SquadAutoCreator.js +64 -0
  111. package/dist/orchestrator/SquadCreator.js +727 -0
  112. package/dist/orchestrator/SquadRegistry.js +28 -0
  113. package/dist/orchestrator/SquadRouter.js +33 -0
  114. package/dist/orchestrator/SquadScoring.js +70 -0
  115. package/dist/orchestrator/SubagentLifecycle.js +90 -0
  116. package/dist/orchestrator/SynthesizerAgent.js +48 -0
  117. package/dist/orchestrator/SystemDoctor.js +224 -0
  118. package/dist/orchestrator/TaskExecutor.js +422 -0
  119. package/dist/orchestrator/TeammateBoard.js +61 -0
  120. package/dist/orchestrator/TestHarness.js +184 -0
  121. package/dist/orchestrator/VoiceManager.js +203 -0
  122. package/dist/orchestrator/VoiceRouter.js +89 -0
  123. package/dist/orchestrator/capability/CapabilityGenesisEngine.js +278 -0
  124. package/dist/orchestrator/capability/CapabilityPackParser.js +223 -0
  125. package/dist/orchestrator/capability/CapabilityPackSchema.js +62 -0
  126. package/dist/orchestrator/capability/CapabilityPackState.js +163 -0
  127. package/dist/orchestrator/providers/AgentProvider.js +2 -0
  128. package/dist/orchestrator/providers/CapabilityProvider.js +12 -0
  129. package/dist/orchestrator/providers/CloudAgentProvider.js +55 -0
  130. package/dist/orchestrator/providers/CloudSkillProvider.js +55 -0
  131. package/dist/orchestrator/providers/CloudSquadProvider.js +55 -0
  132. package/dist/orchestrator/providers/CompositeAgentProvider.js +16 -0
  133. package/dist/orchestrator/providers/CompositeCapabilityProvider.js +25 -0
  134. package/dist/orchestrator/providers/CompositeSkillProvider.js +16 -0
  135. package/dist/orchestrator/providers/CompositeSquadProvider.js +16 -0
  136. package/dist/orchestrator/providers/CompositeWorkflowProvider.js +46 -0
  137. package/dist/orchestrator/providers/FileAgentProvider.js +105 -0
  138. package/dist/orchestrator/providers/FileCapabilityProvider.js +106 -0
  139. package/dist/orchestrator/providers/FileSkillProvider.js +65 -0
  140. package/dist/orchestrator/providers/FileSquadProvider.js +69 -0
  141. package/dist/orchestrator/providers/FileWorkflowProvider.js +103 -0
  142. package/dist/orchestrator/providers/SkillProvider.js +2 -0
  143. package/dist/orchestrator/providers/SquadProvider.js +2 -0
  144. package/dist/orchestrator/toolset/ToolsetGuard.js +69 -0
  145. package/dist/orchestrator/toolset/ToolsetRegistry.js +65 -0
  146. package/dist/orchestrator/toolset/ToolsetSchema.js +21 -0
  147. package/dist/orchestrator/util/AtomicWriter.js +204 -0
  148. package/dist/orchestrator/util/DistributedLock.js +232 -0
  149. package/dist/orchestrator/util/TemplateRenderer.js +87 -0
  150. package/dist/orchestrator/util/WatchdogHeartbeat.js +116 -0
  151. package/dist/orchestrator/workflow/ConditionParser.js +232 -0
  152. package/dist/orchestrator/workflow/WorkflowEngine.js +379 -0
  153. package/dist/orchestrator/workflow/WorkflowParser.js +368 -0
  154. package/dist/orchestrator/workflow/WorkflowSchema.js +65 -0
  155. package/dist/orchestrator/workflow/WorkflowState.js +11 -0
  156. package/dist/reversa/ReversaAgent.js +134 -0
  157. package/dist/reversa/ReversaContracts.js +62 -0
  158. package/dist/reversa/ReversaExecutors.js +65 -0
  159. package/dist/skills/SkillRegistry.js +71 -0
  160. package/dist/squads/SquadManager.js +87 -0
  161. package/dist/test_admin_teams_networks.js +54 -0
  162. package/dist/test_agent_team_skill_network.js +15 -0
  163. package/dist/test_aiobuilder_cli_parity.js +169 -0
  164. package/dist/test_ask_exit.js +73 -0
  165. package/dist/test_atomic_writer.js +209 -0
  166. package/dist/test_autonomous_soak.js +141 -0
  167. package/dist/test_benchmark_engine.js +41 -0
  168. package/dist/test_brain_error_diagnostics.js +51 -0
  169. package/dist/test_brain_fallback_chain.js +93 -0
  170. package/dist/test_capability_genesis_engine.js +225 -0
  171. package/dist/test_capability_pack_schema.js +214 -0
  172. package/dist/test_catalog_quality.js +150 -0
  173. package/dist/test_cli_crud_roundtrip.js +154 -0
  174. package/dist/test_cli_diagnostics.js +131 -0
  175. package/dist/test_cli_doc_parity.js +126 -0
  176. package/dist/test_cli_help_surface.js +106 -0
  177. package/dist/test_cli_service_commands.js +83 -0
  178. package/dist/test_consequence_forecast_brain.js +165 -0
  179. package/dist/test_consequence_forecaster.js +24 -0
  180. package/dist/test_conversation_memory.js +36 -0
  181. package/dist/test_create_entities.js +54 -0
  182. package/dist/test_creator_placeholders_completed.js +177 -0
  183. package/dist/test_cron_manager.js +123 -0
  184. package/dist/test_daemon_sigterm.js +72 -0
  185. package/dist/test_deep_research_capability.js +87 -0
  186. package/dist/test_designmd_import_registry.js +16 -0
  187. package/dist/test_designmd_mode.js +50 -0
  188. package/dist/test_designmd_mode_workspace.js +13 -0
  189. package/dist/test_dist_templates_layout.js +135 -0
  190. package/dist/test_distributed_lock.js +201 -0
  191. package/dist/test_distribution_installability.js +67 -0
  192. package/dist/test_doctor_sandbox_check.js +44 -0
  193. package/dist/test_dream_organizer.js +25 -0
  194. package/dist/test_dual_mode.js +15 -0
  195. package/dist/test_enterprise_agentic_core.js +128 -0
  196. package/dist/test_forecast_brain_wiring.js +87 -0
  197. package/dist/test_gateway_telegram_guardrails.js +52 -0
  198. package/dist/test_governance.js +34 -0
  199. package/dist/test_governance_advanced.js +75 -0
  200. package/dist/test_governance_scope_ledger.js +147 -0
  201. package/dist/test_governance_v13_policies.js +44 -0
  202. package/dist/test_guided_creator_cli.js +100 -0
  203. package/dist/test_host_install_e2e.js +324 -0
  204. package/dist/test_host_installer.js +259 -0
  205. package/dist/test_host_installers_gemini_codex.js +95 -0
  206. package/dist/test_host_uninstaller.js +295 -0
  207. package/dist/test_install_flow.js +70 -0
  208. package/dist/test_install_flow_host_validation.js +143 -0
  209. package/dist/test_install_wizard.js +272 -0
  210. package/dist/test_integration_gemini_live.js +95 -0
  211. package/dist/test_integration_http_trigger_live.js +154 -0
  212. package/dist/test_integration_telegram_live.js +102 -0
  213. package/dist/test_job_lifecycle.js +16 -0
  214. package/dist/test_memory_orchestrator.js +33 -0
  215. package/dist/test_memory_promotion.js +36 -0
  216. package/dist/test_memory_retention.js +37 -0
  217. package/dist/test_mission_checkpoint.js +204 -0
  218. package/dist/test_multi_host_docs_parity.js +125 -0
  219. package/dist/test_openlife_auto_creator_routing.js +69 -0
  220. package/dist/test_openlife_evolution_surface.js +77 -0
  221. package/dist/test_openlife_gatekeeper_routing.js +15 -0
  222. package/dist/test_openlife_routing_surface.js +27 -0
  223. package/dist/test_openlife_runtime_source_truth.js +25 -0
  224. package/dist/test_operating_system.js +45 -0
  225. package/dist/test_optimization_loop.js +38 -0
  226. package/dist/test_orchestration_assets_lifecycle.js +78 -0
  227. package/dist/test_outcome_simulator.js +38 -0
  228. package/dist/test_performance_latency.js +215 -0
  229. package/dist/test_performance_scorecard.js +38 -0
  230. package/dist/test_phase1_check_exit.js +103 -0
  231. package/dist/test_phase6_board.js +31 -0
  232. package/dist/test_phase6_cadence.js +29 -0
  233. package/dist/test_phase6_ops.js +37 -0
  234. package/dist/test_post_mission_evaluation.js +190 -0
  235. package/dist/test_process_sandbox.js +88 -0
  236. package/dist/test_profile_toolset_mcp.js +125 -0
  237. package/dist/test_queue_scheduler.js +239 -0
  238. package/dist/test_release_gate.js +23 -0
  239. package/dist/test_remote_publish.js +193 -0
  240. package/dist/test_reversa_contracts_e2e.js +48 -0
  241. package/dist/test_reversa_export_and_strict.js +51 -0
  242. package/dist/test_reversa_full_execution.js +12 -0
  243. package/dist/test_reversa_lite.js +9 -0
  244. package/dist/test_royal_stack_golden.js +179 -0
  245. package/dist/test_runtime_health_backoff.js +154 -0
  246. package/dist/test_runtime_policy.js +26 -0
  247. package/dist/test_runtime_probe.js +19 -0
  248. package/dist/test_runtime_profile_oauth_only.js +262 -0
  249. package/dist/test_runtime_registry.js +11 -0
  250. package/dist/test_security_download_and_scan.js +103 -0
  251. package/dist/test_security_download_guard.js +14 -0
  252. package/dist/test_service_command_surface.js +12 -0
  253. package/dist/test_service_completion_policy.js +32 -0
  254. package/dist/test_service_guardrails_delete.js +12 -0
  255. package/dist/test_service_mode_explicit_only.js +174 -0
  256. package/dist/test_sources_import_ref.js +46 -0
  257. package/dist/test_sources_scaffold.js +43 -0
  258. package/dist/test_squad_skill_creator.js +305 -0
  259. package/dist/test_squad_skill_design_llm.js +176 -0
  260. package/dist/test_subsystems_org_state.js +271 -0
  261. package/dist/test_subsystems_promotion_memory_assets.js +343 -0
  262. package/dist/test_subsystems_routing_governance.js +234 -0
  263. package/dist/test_task_executor_sandbox_optin.js +127 -0
  264. package/dist/test_teammate_learning.js +15 -0
  265. package/dist/test_telegram_delete_guardrail.js +21 -0
  266. package/dist/test_toolset_enforcement.js +188 -0
  267. package/dist/test_trigger_basic_auth.js +112 -0
  268. package/dist/test_util/doc_parity.js +120 -0
  269. package/dist/test_v15_e2e_integration.js +207 -0
  270. package/dist/test_watchdog_heartbeat.js +152 -0
  271. package/dist/test_workflow_condition_parser.js +63 -0
  272. package/dist/test_workflow_e2e.js +240 -0
  273. package/dist/test_workflow_engine.js +330 -0
  274. package/dist/test_workflow_parser.js +245 -0
  275. package/dist/test_workflow_schema_backward_compat.js +197 -0
  276. package/dist-templates/README.md +91 -0
  277. package/dist-templates/claude-code/agents/openlife-atlas.md +52 -0
  278. package/dist-templates/claude-code/agents/openlife-forge.md +42 -0
  279. package/dist-templates/claude-code/agents/openlife-genesis.md +59 -0
  280. package/dist-templates/claude-code/agents/openlife-lyra.md +40 -0
  281. package/dist-templates/claude-code/agents/openlife-maestro.md +45 -0
  282. package/dist-templates/claude-code/commands/openlife/ask.md +14 -0
  283. package/dist-templates/claude-code/commands/openlife/doctor.md +19 -0
  284. package/dist-templates/claude-code/commands/openlife/dream.md +20 -0
  285. package/dist-templates/claude-code/commands/openlife/status.md +14 -0
  286. package/dist-templates/claude-code/mcp/openlife-orchestrator.json +46 -0
  287. package/dist-templates/codex/README.md +7 -0
  288. package/dist-templates/codex/agents/openlife-atlas.md +52 -0
  289. package/dist-templates/codex/agents/openlife-forge.md +42 -0
  290. package/dist-templates/codex/agents/openlife-genesis.md +59 -0
  291. package/dist-templates/codex/agents/openlife-lyra.md +40 -0
  292. package/dist-templates/codex/agents/openlife-maestro.md +45 -0
  293. package/dist-templates/codex/commands/openlife/ask.md +14 -0
  294. package/dist-templates/codex/commands/openlife/doctor.md +19 -0
  295. package/dist-templates/codex/commands/openlife/dream.md +20 -0
  296. package/dist-templates/codex/commands/openlife/status.md +14 -0
  297. package/dist-templates/codex/mcp/openlife-orchestrator.json +46 -0
  298. package/dist-templates/gemini-cli/README.md +8 -0
  299. package/dist-templates/gemini-cli/agents/openlife-atlas.md +52 -0
  300. package/dist-templates/gemini-cli/agents/openlife-forge.md +42 -0
  301. package/dist-templates/gemini-cli/agents/openlife-genesis.md +59 -0
  302. package/dist-templates/gemini-cli/agents/openlife-lyra.md +40 -0
  303. package/dist-templates/gemini-cli/agents/openlife-maestro.md +45 -0
  304. package/dist-templates/gemini-cli/commands/openlife/ask.md +14 -0
  305. package/dist-templates/gemini-cli/commands/openlife/doctor.md +19 -0
  306. package/dist-templates/gemini-cli/commands/openlife/dream.md +20 -0
  307. package/dist-templates/gemini-cli/commands/openlife/status.md +14 -0
  308. package/dist-templates/gemini-cli/mcp/openlife-orchestrator.json +46 -0
  309. package/dist-templates/skill-template/README.md +34 -0
  310. package/dist-templates/skill-template/SKILL.md.template +59 -0
  311. package/dist-templates/squad-template/README.md +82 -0
  312. package/dist-templates/squad-template/SQUAD.md.template +51 -0
  313. package/dist-templates/squad-template/agent-template.md +51 -0
  314. package/dist-templates/squad-template/checklist-template.md +25 -0
  315. package/dist-templates/squad-template/task-template.md +36 -0
  316. package/dist-templates/workflows/PORTED_WORKFLOWS.md +60 -0
  317. package/dist-templates/workflows/brownfield-discovery.yaml +137 -0
  318. package/dist-templates/workflows/greenfield-fullstack.yaml +132 -0
  319. package/dist-templates/workflows/qa-loop.yaml +125 -0
  320. package/dist-templates/workflows/story-development-cycle.yaml +80 -0
  321. package/docs/CHANGELOG_FEATURE_ROLLOUT_DESIGNMD.md +43 -0
  322. package/docs/EXTERNAL_SOURCES_AND_SECURITY_GUARD.md +33 -0
  323. package/docs/OPENLIFE_AUDIT_2026-05-06.md +170 -0
  324. package/docs/OPENLIFE_CONSOLIDATED_PLAN_2026-05-06.md +299 -0
  325. package/docs/OPENLIFE_DUAL_MODE_IMPLEMENTATION_PLAN.md +205 -0
  326. package/docs/OPENLIFE_EVOLUTION_SURFACE_2026-05-07.md +53 -0
  327. package/docs/OPENLIFE_SKILLS_IMPORT_2026-05-07.json +223 -0
  328. package/docs/OPENLIFE_SQUADS_IMPORT_2026-05-07.json +184 -0
  329. package/docs/PAPERCLIP_OPENLIFE_INVESTIGATION.md +85 -0
  330. package/docs/README.md +28 -0
  331. package/docs/RELEASE_ORGANIZATION_PLAN.md +164 -0
  332. package/docs/audit/CLI-EXECUTION-RESULTS.md +113 -0
  333. package/docs/audit/CLI-MATRIX.md +556 -0
  334. package/docs/audit/DOC-PARITY-GAPS.md +351 -0
  335. package/docs/audit/ORCHESTRATOR-MATRIX.md +136 -0
  336. package/docs/audit/TEST-COVERAGE-GAPS.md +334 -0
  337. package/docs/audit/integrations/SKIPPED.md +101 -0
  338. package/docs/autonomous-install.md +79 -0
  339. package/docs/capability-genesis.md +137 -0
  340. package/docs/capability-pack-schema.md +157 -0
  341. package/docs/commands.md +82 -0
  342. package/docs/deep-research-capability.md +114 -0
  343. package/docs/development/typescript-conventions.md +95 -0
  344. package/docs/host-installers.md +68 -0
  345. package/docs/install/aiobuilder.md +70 -0
  346. package/docs/install/claude-code.md +83 -0
  347. package/docs/install/codex.md +64 -0
  348. package/docs/install/gemini-cli.md +64 -0
  349. package/docs/install/runtime-profiles.md +83 -0
  350. package/docs/openlife-agent-os-blueprint.md +114 -0
  351. package/docs/openlife-install-backlog.md +115 -0
  352. package/docs/openlife-install-spec.md +306 -0
  353. package/docs/operations/CLOUD_CUTOVER_AUDIT.md +37 -0
  354. package/docs/operations/PHASE_PROGRESS_CONTINUATION.md +24 -0
  355. package/docs/performance-benchmarks.md +83 -0
  356. package/docs/planning/v1.3-capability-genesis.md +157 -0
  357. package/docs/plans/2026-05-05-admin-interface-professional-dark-premium-plan.md +84 -0
  358. package/docs/plans/2026-05-05-openlife-autonomous-domain-marketplace-masterplan.md +122 -0
  359. package/docs/quickstart.md +60 -0
  360. package/docs/release-process.md +236 -0
  361. package/docs/roadmap/OPENLIFE_MASTER_PLAN_CLOUD_V3.md +97 -0
  362. package/docs/sandboxing-research.md +117 -0
  363. package/docs/stories/epic-feature-audit/1.1.story.md +84 -0
  364. package/docs/stories/epic-feature-audit/1.2.story.md +102 -0
  365. package/docs/stories/epic-feature-audit/1.3.story.md +93 -0
  366. package/docs/stories/epic-feature-audit/1.5.story.md +121 -0
  367. package/docs/stories/epic-feature-audit/1.6.story.md +80 -0
  368. package/docs/stories/epic-feature-completeness/2.1.story.md +70 -0
  369. package/docs/stories/epic-feature-completeness/2.2.story.md +49 -0
  370. package/docs/stories/epic-feature-completeness/2.3.story.md +74 -0
  371. package/docs/stories/epic-feature-completeness/2.4.story.md +71 -0
  372. package/docs/stories/epic-feature-completeness/3.1.story.md +56 -0
  373. package/docs/stories/epic-feature-completeness/3.2.story.md +80 -0
  374. package/docs/stories/epic-feature-completeness/3.3.story.md +68 -0
  375. package/docs/stories/epic-feature-completeness/3.4.story.md +71 -0
  376. package/docs/stories/epic-feature-completeness/3.5.story.md +72 -0
  377. package/docs/stories/epic-feature-completeness/3.6.story.md +69 -0
  378. package/docs/stories/epic-feature-completeness/3.7.story.md +68 -0
  379. package/docs/stories/epic-feature-completeness/3.8.story.md +57 -0
  380. package/docs/toolset-enforcement.md +122 -0
  381. package/docs/v1.4-changelog.md +159 -0
  382. package/docs/v1.5-changelog.md +106 -0
  383. package/docs/v1.5-roadmap.md +121 -0
  384. package/docs/v1.6-changelog.md +67 -0
  385. package/docs/v1.6-roadmap.md +89 -0
  386. package/docs/v1.7-changelog.md +98 -0
  387. package/docs/workflow-schema.md +177 -0
  388. package/package.json +177 -0
  389. package/scripts/clean-test-pollution.js +61 -0
  390. package/scripts/openlife-agent-start.sh +6 -0
  391. package/scripts/openlife-agent.service.example +13 -0
  392. package/scripts/openlife-agent.supervisord.conf.example +8 -0
  393. package/scripts/openlife-autonomous-install.sh +29 -0
  394. package/scripts/postinstall-check.sh +37 -0
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ /**
3
+ * test_guided_creator_cli.ts — Stories 3.2 + 3.3
4
+ *
5
+ * Spawns the CLI to verify:
6
+ * 1. `openlife create --help` lists the 5 sub-commands
7
+ * 2. `openlife create capability "<desc>"` invokes the GenesisEngine
8
+ * and produces a draft pack (against a sandbox catalogRoot via
9
+ * OPENLIFE_STATE_DIR + working in a temp cwd)
10
+ * 3. `openlife aiobuilder create-capability` exposes the same handler
11
+ * 4. `openlife create workflow <id>` returns the stub guidance
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ const child_process_1 = require("child_process");
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const os = __importStar(require("os"));
51
+ const CLI = path.join(process.cwd(), 'dist', 'index.js');
52
+ function assertTrue(cond, label) {
53
+ if (!cond)
54
+ throw new Error(`ASSERT_FAILED[${label}]`);
55
+ }
56
+ function runCli(args, cwd) {
57
+ const r = (0, child_process_1.spawnSync)('node', [CLI, ...args], { cwd, encoding: 'utf-8', timeout: 30000 });
58
+ return { ok: r.status === 0, status: r.status, out: (r.stdout || '') + (r.stderr || '') };
59
+ }
60
+ // ── Scenario 1: `create --help` lists sub-commands ──────────────────
61
+ const h = runCli(['create', '--help']);
62
+ assertTrue(h.ok, `create --help ok (status=${h.status})`);
63
+ assertTrue(/capability /.test(h.out), 'create capability subcommand listed');
64
+ assertTrue(/squad /.test(h.out), 'create squad subcommand listed');
65
+ assertTrue(/skill /.test(h.out), 'create skill subcommand listed');
66
+ assertTrue(/agent /.test(h.out), 'create agent subcommand listed');
67
+ assertTrue(/workflow /.test(h.out), 'create workflow subcommand listed');
68
+ console.log('[3.2] create --help lists 5 sub-commands ✓');
69
+ // ── Scenario 2: aiobuilder create-capability --help ─────────────────
70
+ const ah = runCli(['aiobuilder', 'create-capability', '--help']);
71
+ assertTrue(ah.ok, `aiobuilder create-capability --help ok (status=${ah.status})`);
72
+ assertTrue(/--mode/.test(ah.out), 'mode option documented');
73
+ assertTrue(/--actor/.test(ah.out), 'actor option documented');
74
+ console.log('[3.3] aiobuilder create-capability --help works ✓');
75
+ // ── Scenario 3: end-to-end create capability in temp cwd ────────────
76
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'guided-creator-'));
77
+ try {
78
+ // Cli writes to <cwd>/.catalog/capabilities/<id>/ and <cwd>/.openlife/...
79
+ const r = runCli([
80
+ 'create', 'capability', 'integration test brief',
81
+ '--id', 'guided-test-pack',
82
+ '--mode', 'quick',
83
+ '--actor', 'cli-test',
84
+ '--skills', 'guided-test-skill',
85
+ ], tmp);
86
+ assertTrue(r.ok, `create capability ok (status=${r.status})\nout: ${r.out.slice(0, 500)}`);
87
+ const packDir = path.join(tmp, '.catalog', 'capabilities', 'guided-test-pack');
88
+ assertTrue(fs.existsSync(path.join(packDir, 'capability.yaml')), 'capability.yaml written');
89
+ assertTrue(fs.existsSync(path.join(packDir, 'INDEX.md')), 'INDEX.md written');
90
+ console.log('[3.3] end-to-end create capability ✓');
91
+ // ── Scenario 4: workflow stub returns expected guidance ───────────
92
+ const wf = runCli(['create', 'workflow', 'some-id'], tmp);
93
+ assertTrue(!wf.ok, 'create workflow returns non-zero');
94
+ assertTrue(/use_create_capability/.test(wf.out), 'workflow stub points to capability');
95
+ console.log('[3.2] create workflow stub guidance ✓');
96
+ }
97
+ finally {
98
+ fs.rmSync(tmp, { recursive: true, force: true });
99
+ }
100
+ console.log('TEST_GUIDED_CREATOR_CLI_OK');
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /*
37
+ * Story 3.7 — Multi-host installer E2E (spawned CLI) regression test.
38
+ *
39
+ * The unit tests for HostInstaller (src/test_host_installer.ts) and host
40
+ * validation (src/test_install_flow_host_validation.ts) cover the classes in
41
+ * isolation. This test SPAWNS `node bin/openlife.js` against a temp dir to
42
+ * validate the full stack: Commander flag parsing, lazy require chain, JSON
43
+ * output, exit codes, and side effects on disk.
44
+ *
45
+ * Scenarios:
46
+ * 1. claude-code install + status + uninstall full cycle
47
+ * 2. gemini-cli host degrades gracefully (state created, host install skipped)
48
+ * 3. codex host degrades gracefully (same as #2)
49
+ * 4. invalid host (e.g. 'cursor') yields a clear error
50
+ * 5. uninstall in a clean project is idempotent (all skipped-not-found)
51
+ * 6. reinstall is idempotent (no duplicated agent files on disk)
52
+ *
53
+ * NOTE on timeouts: CLI cold start is ~5-10s in WSL due to the require tree
54
+ * (Brain, Gateway, etc. — even though most are lazy in command handlers, some
55
+ * top-level imports still resolve). Each spawn gets a 60s shell timeout which
56
+ * is comfortably above observed worst-case.
57
+ */
58
+ const child_process_1 = require("child_process");
59
+ const fs = __importStar(require("fs"));
60
+ const path = __importStar(require("path"));
61
+ const os = __importStar(require("os"));
62
+ const CLI = path.join(process.cwd(), 'dist', 'index.js');
63
+ const SPAWN_TIMEOUT_MS = Number(process.env.OPENLIFE_TEST_E2E_TIMEOUT_MS || 60000);
64
+ function assert(cond, msg) {
65
+ if (!cond)
66
+ throw new Error(`ASSERTION_FAILED: ${msg}`);
67
+ }
68
+ function mkTemp() {
69
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'openlife-e2e-test-'));
70
+ }
71
+ function runCli(args, cwd, timeoutMs = SPAWN_TIMEOUT_MS) {
72
+ return new Promise((resolve) => {
73
+ const t0 = Date.now();
74
+ // Strip TELEGRAM_BOT_TOKEN and OPENAI_API_KEY so the CLI does not try to
75
+ // bind the gateway or any real model — tests are pure filesystem ops.
76
+ // We DO need PATH/HOME for Node.
77
+ const childEnv = { ...process.env };
78
+ delete childEnv.TELEGRAM_BOT_TOKEN;
79
+ const child = (0, child_process_1.spawn)('node', [CLI, ...args], {
80
+ cwd,
81
+ stdio: ['ignore', 'pipe', 'pipe'],
82
+ env: childEnv
83
+ });
84
+ let stdout = '';
85
+ let stderr = '';
86
+ child.stdout?.on('data', (d) => { stdout += d.toString(); });
87
+ child.stderr?.on('data', (d) => { stderr += d.toString(); });
88
+ let timedOut = false;
89
+ const killer = setTimeout(() => {
90
+ timedOut = true;
91
+ child.kill('SIGKILL');
92
+ }, timeoutMs);
93
+ child.on('exit', (code, signal) => {
94
+ clearTimeout(killer);
95
+ resolve({ code, signal, stdout, stderr, elapsed: Date.now() - t0, timedOut });
96
+ });
97
+ });
98
+ }
99
+ // Extract the LARGEST top-level JSON object from a stdout blob. The CLI emits
100
+ // banners (installationBanner, summary lines) plus a JSON payload that itself
101
+ // contains nested objects. We want the outer envelope, so we scan for '{' at
102
+ // indentation level 0 (depth resets between scans) and pick the longest match
103
+ // whose parser succeeds.
104
+ function extractLastJsonObject(blob) {
105
+ let best = null;
106
+ let bestLen = 0;
107
+ let i = 0;
108
+ while (i < blob.length) {
109
+ if (blob[i] !== '{') {
110
+ i++;
111
+ continue;
112
+ }
113
+ let depth = 0;
114
+ let end = -1;
115
+ for (let j = i; j < blob.length; j++) {
116
+ const c = blob[j];
117
+ if (c === '{')
118
+ depth++;
119
+ else if (c === '}') {
120
+ depth--;
121
+ if (depth === 0) {
122
+ end = j;
123
+ break;
124
+ }
125
+ }
126
+ }
127
+ if (end === -1)
128
+ break;
129
+ const slice = blob.slice(i, end + 1);
130
+ try {
131
+ const parsed = JSON.parse(slice);
132
+ if (parsed && typeof parsed === 'object' && slice.length >= bestLen) {
133
+ best = parsed;
134
+ bestLen = slice.length;
135
+ }
136
+ }
137
+ catch { /* ignore */ }
138
+ // Skip past this object — nested duplicates of the same payload are
139
+ // shorter, so they won't beat `best` once we capture the outer one.
140
+ i = end + 1;
141
+ }
142
+ return best;
143
+ }
144
+ // ----- Scenario 1: claude-code install + status + uninstall full cycle -----
145
+ async function scenario1_claudeCodeFullCycle() {
146
+ const tempRoot = mkTemp();
147
+ try {
148
+ // 1. system setup --host claude-code
149
+ const installRes = await runCli(['system', 'setup', '--profile', 'framework', '--host', 'claude-code', '--skip-doctor'], tempRoot);
150
+ if (installRes.timedOut) {
151
+ throw new Error(`SCENARIO1_INSTALL_TIMEOUT after ${installRes.elapsed}ms`);
152
+ }
153
+ assert(installRes.code === 0, `scenario1: setup should exit 0; got code=${installRes.code}, stderr=${installRes.stderr.slice(0, 400)}`);
154
+ // Side effects on disk
155
+ const manifestPath = path.join(tempRoot, '.openlife', 'install-manifest.json');
156
+ assert(fs.existsSync(manifestPath), `scenario1: install-manifest.json missing at ${manifestPath}`);
157
+ const maestro = path.join(tempRoot, '.claude', 'agents', 'openlife-maestro.md');
158
+ assert(fs.existsSync(maestro), `scenario1: openlife-maestro.md missing at ${maestro}`);
159
+ const statusCmd = path.join(tempRoot, '.claude', 'commands', 'openlife', 'status.md');
160
+ assert(fs.existsSync(statusCmd), `scenario1: commands/openlife/status.md missing at ${statusCmd}`);
161
+ const mcpSnippet = path.join(tempRoot, '.openlife', 'install-mcp-snippet.json');
162
+ assert(fs.existsSync(mcpSnippet), `scenario1: install-mcp-snippet.json missing at ${mcpSnippet}`);
163
+ // 2. system status — should reflect tempRoot via process.cwd()
164
+ const statusRes = await runCli(['system', 'status'], tempRoot);
165
+ if (statusRes.timedOut)
166
+ throw new Error(`SCENARIO1_STATUS_TIMEOUT after ${statusRes.elapsed}ms`);
167
+ assert(statusRes.code === 0, `scenario1: status should exit 0; got ${statusRes.code}`);
168
+ const statusJson = extractLastJsonObject(statusRes.stdout);
169
+ assert(statusJson !== null, `scenario1: status should emit JSON; got: ${statusRes.stdout.slice(0, 400)}`);
170
+ assert(statusJson.hasInstallManifest === true, `scenario1: status.hasInstallManifest should be true; got ${JSON.stringify(statusJson)}`);
171
+ // 3. system uninstall --host claude-code
172
+ const uninstallRes = await runCli(['system', 'uninstall', '--host', 'claude-code'], tempRoot);
173
+ if (uninstallRes.timedOut)
174
+ throw new Error(`SCENARIO1_UNINSTALL_TIMEOUT after ${uninstallRes.elapsed}ms`);
175
+ assert(uninstallRes.code === 0, `scenario1: uninstall should exit 0; got ${uninstallRes.code}, stderr=${uninstallRes.stderr.slice(0, 400)}`);
176
+ // Host files should be gone…
177
+ assert(!fs.existsSync(maestro), `scenario1: openlife-maestro.md should be removed; still at ${maestro}`);
178
+ // commands/openlife may either be gone or empty — the unit test asserts directory is removed when empty.
179
+ const commandsDir = path.join(tempRoot, '.claude', 'commands', 'openlife');
180
+ if (fs.existsSync(commandsDir)) {
181
+ const remaining = fs.readdirSync(commandsDir);
182
+ assert(remaining.length === 0, `scenario1: commands/openlife should be empty or removed; still contains: ${remaining.join(',')}`);
183
+ }
184
+ assert(!fs.existsSync(mcpSnippet), `scenario1: install-mcp-snippet.json should be removed; still at ${mcpSnippet}`);
185
+ // …but .openlife state must be preserved (manifest survives).
186
+ assert(fs.existsSync(manifestPath), `scenario1: install-manifest.json should be preserved after uninstall; missing at ${manifestPath}`);
187
+ assert(fs.existsSync(path.join(tempRoot, '.openlife')), `scenario1: .openlife dir should be preserved after uninstall`);
188
+ }
189
+ finally {
190
+ fs.rmSync(tempRoot, { recursive: true, force: true });
191
+ }
192
+ }
193
+ // ----- Scenario 2: gemini-cli degrades gracefully -----
194
+ async function scenario2_geminiCliDegrades() {
195
+ const tempRoot = mkTemp();
196
+ try {
197
+ const res = await runCli(['system', 'setup', '--profile', 'framework', '--host', 'gemini-cli', '--skip-doctor'], tempRoot);
198
+ if (res.timedOut)
199
+ throw new Error(`SCENARIO2_TIMEOUT after ${res.elapsed}ms`);
200
+ assert(res.code === 0, `scenario2: setup should exit 0 even for unsupported host; got ${res.code}, stderr=${res.stderr.slice(0, 400)}`);
201
+ // .openlife state created
202
+ const manifestPath = path.join(tempRoot, '.openlife', 'install-manifest.json');
203
+ assert(fs.existsSync(manifestPath), `scenario2: install-manifest.json should still be created; missing at ${manifestPath}`);
204
+ // .claude/ should NOT exist (no host install for gemini-cli)
205
+ const claudeDir = path.join(tempRoot, '.claude');
206
+ assert(!fs.existsSync(claudeDir), `scenario2: .claude/ should NOT be created for gemini-cli; found at ${claudeDir}`);
207
+ // Output should hint at the graceful skip somewhere
208
+ const combined = (res.stdout + '\n' + res.stderr).toLowerCase();
209
+ assert(combined.includes('skipped') ||
210
+ combined.includes('host_not_yet_supported') ||
211
+ combined.includes('not yet supported') ||
212
+ combined.includes('host install'), `scenario2: output should mention skip/unsupported; got stdout=${res.stdout.slice(0, 600)}`);
213
+ }
214
+ finally {
215
+ fs.rmSync(tempRoot, { recursive: true, force: true });
216
+ }
217
+ }
218
+ // ----- Scenario 3: codex degrades gracefully (same shape as #2) -----
219
+ async function scenario3_codexDegrades() {
220
+ const tempRoot = mkTemp();
221
+ try {
222
+ const res = await runCli(['system', 'setup', '--profile', 'framework', '--host', 'codex', '--skip-doctor'], tempRoot);
223
+ if (res.timedOut)
224
+ throw new Error(`SCENARIO3_TIMEOUT after ${res.elapsed}ms`);
225
+ assert(res.code === 0, `scenario3: setup should exit 0 even for unsupported host; got ${res.code}, stderr=${res.stderr.slice(0, 400)}`);
226
+ const manifestPath = path.join(tempRoot, '.openlife', 'install-manifest.json');
227
+ assert(fs.existsSync(manifestPath), `scenario3: install-manifest.json missing at ${manifestPath}`);
228
+ const claudeDir = path.join(tempRoot, '.claude');
229
+ assert(!fs.existsSync(claudeDir), `scenario3: .claude/ should NOT be created for codex; found at ${claudeDir}`);
230
+ const combined = (res.stdout + '\n' + res.stderr).toLowerCase();
231
+ assert(combined.includes('skipped') ||
232
+ combined.includes('host_not_yet_supported') ||
233
+ combined.includes('not yet supported') ||
234
+ combined.includes('host install'), `scenario3: output should mention skip/unsupported; got stdout=${res.stdout.slice(0, 600)}`);
235
+ }
236
+ finally {
237
+ fs.rmSync(tempRoot, { recursive: true, force: true });
238
+ }
239
+ }
240
+ // ----- Scenario 4: invalid host returns clear error -----
241
+ async function scenario4_invalidHostFails() {
242
+ const tempRoot = mkTemp();
243
+ try {
244
+ const res = await runCli(['system', 'setup', '--profile', 'framework', '--host', 'cursor', '--skip-doctor'], tempRoot);
245
+ if (res.timedOut)
246
+ throw new Error(`SCENARIO4_TIMEOUT after ${res.elapsed}ms`);
247
+ // Story 3.1: invalid host must throw INVALID_HOST. InstallFlow.run() throws,
248
+ // which bubbles up unhandled in the action handler. The process should exit
249
+ // non-zero (either via thrown error or signal) and/or surface a clear msg.
250
+ const combined = (res.stdout + '\n' + res.stderr).toLowerCase();
251
+ const mentionsInvalid = combined.includes('invalid_host') || combined.includes('invalid host');
252
+ const mentionsCursor = combined.includes('cursor');
253
+ const mentionsValidHosts = combined.includes('claude-code') && combined.includes('gemini-cli');
254
+ assert(mentionsInvalid || (mentionsCursor && mentionsValidHosts), `scenario4: output should clearly identify invalid host 'cursor'; got stdout=${res.stdout.slice(0, 400)} stderr=${res.stderr.slice(0, 400)}`);
255
+ assert(res.code !== 0, `scenario4: invalid host should yield non-zero exit; got code=${res.code}`);
256
+ }
257
+ finally {
258
+ fs.rmSync(tempRoot, { recursive: true, force: true });
259
+ }
260
+ }
261
+ // ----- Scenario 5: uninstall on clean project is idempotent -----
262
+ async function scenario5_uninstallOnCleanProject() {
263
+ const tempRoot = mkTemp();
264
+ try {
265
+ const res = await runCli(['system', 'uninstall', '--host', 'claude-code'], tempRoot);
266
+ if (res.timedOut)
267
+ throw new Error(`SCENARIO5_TIMEOUT after ${res.elapsed}ms`);
268
+ assert(res.code === 0, `scenario5: uninstall on clean project should exit 0; got ${res.code}, stderr=${res.stderr.slice(0, 400)}`);
269
+ const json = extractLastJsonObject(res.stdout);
270
+ assert(json !== null, `scenario5: uninstall should emit JSON; got: ${res.stdout.slice(0, 400)}`);
271
+ assert(json.ok === true, `scenario5: uninstall should report ok=true; got ${JSON.stringify(json)}`);
272
+ // Every file action should be 'skipped-not-found' on a clean dir.
273
+ const files = Array.isArray(json.files) ? json.files : [];
274
+ assert(files.length > 0, `scenario5: uninstall should report at least one file action; got ${JSON.stringify(json)}`);
275
+ const allSkipped = files.every((f) => f.action === 'skipped-not-found');
276
+ assert(allSkipped, `scenario5: all actions should be 'skipped-not-found' on clean dir; got ${JSON.stringify(files.map((f) => f.action))}`);
277
+ }
278
+ finally {
279
+ fs.rmSync(tempRoot, { recursive: true, force: true });
280
+ }
281
+ }
282
+ // ----- Scenario 6: reinstall is idempotent (no duplicate agents) -----
283
+ async function scenario6_reinstallIdempotent() {
284
+ const tempRoot = mkTemp();
285
+ try {
286
+ // First install
287
+ const r1 = await runCli(['system', 'setup', '--profile', 'framework', '--host', 'claude-code', '--skip-doctor'], tempRoot);
288
+ if (r1.timedOut)
289
+ throw new Error(`SCENARIO6_INSTALL1_TIMEOUT after ${r1.elapsed}ms`);
290
+ assert(r1.code === 0, `scenario6: first setup should exit 0; got ${r1.code}`);
291
+ const agentsDir = path.join(tempRoot, '.claude', 'agents');
292
+ const before = fs.readdirSync(agentsDir).filter((f) => f.startsWith('openlife-') && f.endsWith('.md')).sort();
293
+ assert(before.length > 0, `scenario6: should have openlife-*.md agents after first install`);
294
+ // Second install — should be idempotent
295
+ const r2 = await runCli(['system', 'setup', '--profile', 'framework', '--host', 'claude-code', '--skip-doctor'], tempRoot);
296
+ if (r2.timedOut)
297
+ throw new Error(`SCENARIO6_INSTALL2_TIMEOUT after ${r2.elapsed}ms`);
298
+ assert(r2.code === 0, `scenario6: second setup should exit 0; got ${r2.code}`);
299
+ const after = fs.readdirSync(agentsDir).filter((f) => f.startsWith('openlife-') && f.endsWith('.md')).sort();
300
+ assert(after.length === before.length, `scenario6: reinstall should NOT duplicate agents; before=${before.length} (${before.join(',')}) after=${after.length} (${after.join(',')})`);
301
+ assert(JSON.stringify(before) === JSON.stringify(after), `scenario6: agent set should be identical before/after reinstall; before=${JSON.stringify(before)} after=${JSON.stringify(after)}`);
302
+ }
303
+ finally {
304
+ fs.rmSync(tempRoot, { recursive: true, force: true });
305
+ }
306
+ }
307
+ async function main() {
308
+ if (!fs.existsSync(CLI)) {
309
+ throw new Error(`MISSING_BUILD: ${CLI} — run 'npm run build' first`);
310
+ }
311
+ const t0 = Date.now();
312
+ await scenario1_claudeCodeFullCycle();
313
+ await scenario2_geminiCliDegrades();
314
+ await scenario3_codexDegrades();
315
+ await scenario4_invalidHostFails();
316
+ await scenario5_uninstallOnCleanProject();
317
+ await scenario6_reinstallIdempotent();
318
+ const elapsed = Date.now() - t0;
319
+ console.log(`TEST_HOST_INSTALL_E2E_OK (elapsed=${elapsed}ms, scenarios=6)`);
320
+ }
321
+ main().catch((err) => {
322
+ console.error('TEST_HOST_INSTALL_E2E_FAIL:', err?.message || err);
323
+ process.exit(1);
324
+ });