@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,259 @@
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.3 — HostInstaller regression test.
38
+ *
39
+ * Asserts:
40
+ * 1. installForClaudeCode copies the 5 agents, 4 slash commands, and MCP snippet to the right paths
41
+ * 2. Re-running install reports all files as 'skipped-identical' (idempotency)
42
+ * 3. Modifying a destination file then re-installing creates a .bak and reports 'updated'
43
+ * 4. installForGeminiCli throws HostNotYetSupportedError with code 'HOST_NOT_YET_SUPPORTED'
44
+ * 5. installForCodex throws HostNotYetSupportedError
45
+ * 6. install('claude-code', ...) dispatcher works
46
+ * 7. InstallFlow.run({ host: 'claude-code' }) in a temp dir produces host install files AND
47
+ * install-flow-report.json mentions hostInstall
48
+ */
49
+ const fs = __importStar(require("fs"));
50
+ const path = __importStar(require("path"));
51
+ const os = __importStar(require("os"));
52
+ const HostInstaller_1 = require("./cli/HostInstaller");
53
+ const InstallFlow_1 = require("./cli/InstallFlow");
54
+ function assert(cond, msg) {
55
+ if (!cond)
56
+ throw new Error(`ASSERTION_FAILED: ${msg}`);
57
+ }
58
+ function mkTemp(prefix = 'openlife-hostinstaller-test-') {
59
+ return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
60
+ }
61
+ const EXPECTED_AGENTS = [
62
+ 'openlife-maestro.md',
63
+ 'openlife-lyra.md',
64
+ 'openlife-forge.md',
65
+ 'openlife-atlas.md',
66
+ 'openlife-genesis.md'
67
+ ];
68
+ const EXPECTED_COMMANDS = ['status.md', 'ask.md', 'doctor.md', 'dream.md'];
69
+ function testInstallForClaudeCodeCreatesAllFiles() {
70
+ const tempRoot = mkTemp();
71
+ try {
72
+ const installer = new HostInstaller_1.HostInstaller();
73
+ const result = installer.installForClaudeCode({ targetRoot: tempRoot });
74
+ assert(result.host === 'claude-code', `host should be claude-code, got ${result.host}`);
75
+ assert(result.targetRoot === tempRoot, 'targetRoot should round-trip');
76
+ assert(Array.isArray(result.files) && result.files.length > 0, 'files[] should be populated');
77
+ // Agents
78
+ for (const agent of EXPECTED_AGENTS) {
79
+ const dst = path.join(tempRoot, '.claude', 'agents', agent);
80
+ assert(fs.existsSync(dst), `agent file missing: ${dst}`);
81
+ }
82
+ // Commands
83
+ for (const cmd of EXPECTED_COMMANDS) {
84
+ const dst = path.join(tempRoot, '.claude', 'commands', 'openlife', cmd);
85
+ assert(fs.existsSync(dst), `command file missing: ${dst}`);
86
+ }
87
+ // MCP snippet
88
+ const mcpDst = path.join(tempRoot, '.openlife', 'install-mcp-snippet.json');
89
+ assert(fs.existsSync(mcpDst), `mcp snippet missing: ${mcpDst}`);
90
+ assert(result.mcpSnippetPath === mcpDst, `mcpSnippetPath should match staged path; got ${result.mcpSnippetPath}`);
91
+ // Every emitted action should be 'created' on a fresh temp dir.
92
+ const createds = result.files.filter((f) => f.action === 'created').length;
93
+ assert(createds === result.files.length, `all actions should be 'created' on fresh install; got ${createds}/${result.files.length}`);
94
+ }
95
+ finally {
96
+ fs.rmSync(tempRoot, { recursive: true, force: true });
97
+ }
98
+ }
99
+ function testIdempotentReinstall() {
100
+ const tempRoot = mkTemp();
101
+ try {
102
+ const installer = new HostInstaller_1.HostInstaller();
103
+ installer.installForClaudeCode({ targetRoot: tempRoot });
104
+ // Re-run — every action should now be 'skipped-identical'.
105
+ const second = installer.installForClaudeCode({ targetRoot: tempRoot });
106
+ const skipped = second.files.filter((f) => f.action === 'skipped-identical').length;
107
+ assert(skipped === second.files.length, `all actions should be 'skipped-identical' on re-install; got ${skipped}/${second.files.length}: ${JSON.stringify(second.files.map((f) => f.action))}`);
108
+ }
109
+ finally {
110
+ fs.rmSync(tempRoot, { recursive: true, force: true });
111
+ }
112
+ }
113
+ function testUpdatedActionWritesBackup() {
114
+ const tempRoot = mkTemp();
115
+ try {
116
+ const installer = new HostInstaller_1.HostInstaller();
117
+ installer.installForClaudeCode({ targetRoot: tempRoot });
118
+ // Mutate one destination file so the next install sees a diff.
119
+ const target = path.join(tempRoot, '.claude', 'agents', 'openlife-maestro.md');
120
+ assert(fs.existsSync(target), `precondition: ${target} should exist after first install`);
121
+ fs.writeFileSync(target, '# user-edited\n', 'utf-8');
122
+ const second = installer.installForClaudeCode({ targetRoot: tempRoot });
123
+ const updated = second.files.find((f) => f.destination === target);
124
+ assert(updated !== undefined, `expected an action for ${target} in second install`);
125
+ assert(updated.action === 'updated', `expected 'updated' action for mutated file; got '${updated.action}'`);
126
+ assert(typeof updated.backupPath === 'string' && updated.backupPath.endsWith('.bak'), `expected .bak backupPath; got '${updated.backupPath}'`);
127
+ assert(fs.existsSync(updated.backupPath), `backup file should exist on disk: ${updated.backupPath}`);
128
+ const bakContent = fs.readFileSync(updated.backupPath, 'utf-8');
129
+ assert(bakContent === '# user-edited\n', `backup should preserve the user's edit; got: ${bakContent}`);
130
+ }
131
+ finally {
132
+ fs.rmSync(tempRoot, { recursive: true, force: true });
133
+ }
134
+ }
135
+ function testGeminiCliInstallsRealTemplates() {
136
+ // Sprint 2 / Stories 9.3 + 9.5 — gemini-cli no longer throws
137
+ // HostNotYetSupportedError; it now copies dist-templates/gemini-cli/ into
138
+ // the target. The full coverage lives in test_host_installers_gemini_codex.ts.
139
+ // Here we only assert this installer no longer signals "not yet supported".
140
+ const tempRoot = mkTemp();
141
+ try {
142
+ const installer = new HostInstaller_1.HostInstaller();
143
+ let caught = null;
144
+ try {
145
+ installer.installForGeminiCli({ targetRoot: tempRoot });
146
+ }
147
+ catch (err) {
148
+ caught = err;
149
+ }
150
+ assert(!(caught instanceof HostInstaller_1.HostNotYetSupportedError), 'gemini-cli installer should no longer throw HostNotYetSupportedError (Story 9.3)');
151
+ }
152
+ finally {
153
+ fs.rmSync(tempRoot, { recursive: true, force: true });
154
+ }
155
+ }
156
+ function testCodexInstallsRealTemplates() {
157
+ // Sprint 2 / Story 9.4 — codex installer is now real. Mirror of the
158
+ // gemini-cli check above. Detailed assertions live in
159
+ // test_host_installers_gemini_codex.ts.
160
+ const tempRoot = mkTemp();
161
+ try {
162
+ const installer = new HostInstaller_1.HostInstaller();
163
+ let caught = null;
164
+ try {
165
+ installer.installForCodex({ targetRoot: tempRoot });
166
+ }
167
+ catch (err) {
168
+ caught = err;
169
+ }
170
+ assert(!(caught instanceof HostInstaller_1.HostNotYetSupportedError), 'codex installer should no longer throw HostNotYetSupportedError (Story 9.4)');
171
+ }
172
+ finally {
173
+ fs.rmSync(tempRoot, { recursive: true, force: true });
174
+ }
175
+ }
176
+ function testDispatcherDispatchesClaudeCode() {
177
+ const tempRoot = mkTemp();
178
+ try {
179
+ const installer = new HostInstaller_1.HostInstaller();
180
+ const result = installer.install('claude-code', { targetRoot: tempRoot });
181
+ assert(result.host === 'claude-code', `dispatcher should produce claude-code result; got ${result.host}`);
182
+ assert(fs.existsSync(path.join(tempRoot, '.claude', 'agents', 'openlife-maestro.md')), 'dispatcher should have produced agent files');
183
+ // Sprint 2 / Stories 9.3 + 9.4 — gemini-cli and codex are now real
184
+ // installers. The dispatcher should produce a real result, not throw.
185
+ const geminiResult = installer.install('gemini-cli', { targetRoot: tempRoot });
186
+ assert(geminiResult.host === 'gemini-cli', `dispatcher should produce gemini-cli result; got ${geminiResult.host}`);
187
+ const codexResult = installer.install('codex', { targetRoot: tempRoot });
188
+ assert(codexResult.host === 'codex', `dispatcher should produce codex result; got ${codexResult.host}`);
189
+ }
190
+ finally {
191
+ fs.rmSync(tempRoot, { recursive: true, force: true });
192
+ }
193
+ }
194
+ function testInstallFlowWiresHostInstaller() {
195
+ const tempRoot = mkTemp();
196
+ try {
197
+ const flow = new InstallFlow_1.InstallFlow(tempRoot);
198
+ const result = flow.run({ profile: 'framework', host: 'claude-code', skipDoctor: true });
199
+ assert(result.hostInstall !== undefined, 'InstallFlow result should include hostInstall');
200
+ // Should NOT be the skipped envelope for claude-code.
201
+ assert(!('skipped' in result.hostInstall && result.hostInstall.skipped), `claude-code host install should not be skipped; got: ${JSON.stringify(result.hostInstall)}`);
202
+ const hi = result.hostInstall;
203
+ assert(hi.host === 'claude-code', `hostInstall.host should be claude-code; got ${hi.host}`);
204
+ assert(Array.isArray(hi.files) && hi.files.length > 0, 'hostInstall.files should be populated');
205
+ // Real files on disk
206
+ for (const agent of EXPECTED_AGENTS) {
207
+ assert(fs.existsSync(path.join(tempRoot, '.claude', 'agents', agent)), `InstallFlow should have produced agent: ${agent}`);
208
+ }
209
+ for (const cmd of EXPECTED_COMMANDS) {
210
+ assert(fs.existsSync(path.join(tempRoot, '.claude', 'commands', 'openlife', cmd)), `InstallFlow should have produced command: ${cmd}`);
211
+ }
212
+ // install-flow-report.json must mention hostInstall
213
+ assert(fs.existsSync(result.reportPath), `report should be written at ${result.reportPath}`);
214
+ const reportRaw = fs.readFileSync(result.reportPath, 'utf-8');
215
+ assert(reportRaw.includes('hostInstall'), `install-flow-report.json should mention hostInstall; got: ${reportRaw.slice(0, 200)}...`);
216
+ const parsed = JSON.parse(reportRaw);
217
+ assert(parsed.hostInstall, 'parsed report.hostInstall should be truthy');
218
+ assert(parsed.hostInstall.host === 'claude-code', "report.hostInstall.host should be 'claude-code'");
219
+ // renderSummary should mention the host install line.
220
+ const summary = flow.renderSummary(result).join('\n');
221
+ assert(summary.includes('Host install:'), `renderSummary should mention 'Host install:'; got:\n${summary}`);
222
+ }
223
+ finally {
224
+ fs.rmSync(tempRoot, { recursive: true, force: true });
225
+ }
226
+ }
227
+ function testInstallFlowDegradesForUnsupportedHost() {
228
+ // Sprint 2 / Stories 9.3 + 9.4 — gemini-cli is no longer "unsupported", it
229
+ // is fully installable. This test now asserts the host install succeeded
230
+ // and a real report was written, instead of asserting graceful degradation.
231
+ const tempRoot = mkTemp();
232
+ try {
233
+ const flow = new InstallFlow_1.InstallFlow(tempRoot);
234
+ const result = flow.run({ profile: 'framework', host: 'gemini-cli', skipDoctor: true });
235
+ assert(result.hostInstall !== undefined, 'InstallFlow result should include hostInstall envelope');
236
+ const envelope = result.hostInstall;
237
+ assert(envelope.skipped !== true, `gemini-cli is now supported; envelope should not be skipped (got: ${JSON.stringify(envelope)})`);
238
+ assert(envelope.host === 'gemini-cli', `envelope host should be 'gemini-cli'; got ${envelope.host}`);
239
+ assert(fs.existsSync(result.reportPath), 'install-flow-report.json should be written');
240
+ }
241
+ finally {
242
+ fs.rmSync(tempRoot, { recursive: true, force: true });
243
+ }
244
+ }
245
+ async function main() {
246
+ testInstallForClaudeCodeCreatesAllFiles();
247
+ testIdempotentReinstall();
248
+ testUpdatedActionWritesBackup();
249
+ testGeminiCliInstallsRealTemplates();
250
+ testCodexInstallsRealTemplates();
251
+ testDispatcherDispatchesClaudeCode();
252
+ testInstallFlowWiresHostInstaller();
253
+ testInstallFlowDegradesForUnsupportedHost();
254
+ console.log('TEST_HOST_INSTALLER_OK');
255
+ }
256
+ main().catch((err) => {
257
+ console.error('TEST_HOST_INSTALLER_FAIL:', err?.message || err);
258
+ process.exit(1);
259
+ });
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * test_host_installers_gemini_codex.ts — Stories 9.3 + 9.4 + 9.5
4
+ *
5
+ * Asserts that installForGeminiCli + installForCodex are no longer stubs,
6
+ * mirror the claude-code pattern, and produce reversible uninstall.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ const fs = __importStar(require("fs"));
43
+ const os = __importStar(require("os"));
44
+ const path = __importStar(require("path"));
45
+ const HostInstaller_1 = require("./cli/HostInstaller");
46
+ function assertTrue(cond, label) {
47
+ if (!cond)
48
+ throw new Error(`ASSERT_FAILED[${label}]`);
49
+ }
50
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'host-install-gc-'));
51
+ try {
52
+ const installer = new HostInstaller_1.HostInstaller();
53
+ // ── 1. gemini-cli install populates .gemini/ ────────────────────────
54
+ const target1 = path.join(tmp, 'gemini-host');
55
+ fs.mkdirSync(target1, { recursive: true });
56
+ const r1 = installer.installForGeminiCli({ targetRoot: target1 });
57
+ assertTrue(r1.host === 'gemini-cli', '[9.3] result host');
58
+ assertTrue(fs.existsSync(path.join(target1, '.gemini', 'agents')), '[9.3] .gemini/agents created');
59
+ const agents = fs.readdirSync(path.join(target1, '.gemini', 'agents')).filter((f) => f.startsWith('openlife-'));
60
+ assertTrue(agents.length >= 5, `[9.3] >=5 agents installed (got ${agents.length})`);
61
+ assertTrue(fs.existsSync(path.join(target1, '.gemini', 'commands', 'openlife')), '[9.3] commands namespace created');
62
+ const cmds = fs.readdirSync(path.join(target1, '.gemini', 'commands', 'openlife'));
63
+ assertTrue(cmds.length >= 4, `[9.3] >=4 commands installed (got ${cmds.length})`);
64
+ assertTrue(fs.existsSync(path.join(target1, '.openlife', 'install-mcp-snippet-gemini-cli.json')), '[9.3] mcp snippet staged');
65
+ console.log('[9.3] installForGeminiCli produced .gemini/{agents,commands,mcp} ✓');
66
+ // ── 2. codex install populates .codex/ ─────────────────────────────
67
+ const target2 = path.join(tmp, 'codex-host');
68
+ fs.mkdirSync(target2, { recursive: true });
69
+ const r2 = installer.installForCodex({ targetRoot: target2 });
70
+ assertTrue(r2.host === 'codex', '[9.4] result host');
71
+ assertTrue(fs.existsSync(path.join(target2, '.codex', 'agents')), '[9.4] .codex/agents created');
72
+ assertTrue(fs.existsSync(path.join(target2, '.openlife', 'install-mcp-snippet-codex.json')), '[9.4] mcp snippet staged');
73
+ console.log('[9.4] installForCodex produced .codex/{agents,commands,mcp} ✓');
74
+ // ── 3. uninstall is reversible for gemini-cli ──────────────────────
75
+ const u1 = installer.uninstallForGeminiCli({ targetRoot: target1 });
76
+ assertTrue(u1.host === 'gemini-cli', '[9.3] uninstall result');
77
+ const remainingAgents = fs.existsSync(path.join(target1, '.gemini', 'agents'))
78
+ ? fs.readdirSync(path.join(target1, '.gemini', 'agents')).filter((f) => f.startsWith('openlife-'))
79
+ : [];
80
+ assertTrue(remainingAgents.length === 0, `[9.3] uninstall removes openlife-* agents (got ${remainingAgents.length})`);
81
+ assertTrue(!fs.existsSync(path.join(target1, '.openlife', 'install-mcp-snippet-gemini-cli.json')), '[9.3] uninstall removes mcp snippet');
82
+ console.log('[9.3] uninstallForGeminiCli reversible ✓');
83
+ // ── 4. uninstall is reversible for codex ───────────────────────────
84
+ const u2 = installer.uninstallForCodex({ targetRoot: target2 });
85
+ assertTrue(u2.host === 'codex', '[9.4] uninstall result');
86
+ console.log('[9.4] uninstallForCodex reversible ✓');
87
+ // ── 5. dist-templates layout was scaffolded by 9.5 ─────────────────
88
+ assertTrue(fs.existsSync(path.join(process.cwd(), 'dist-templates', 'gemini-cli', 'agents')), '[9.5] dist-templates/gemini-cli/agents exists');
89
+ assertTrue(fs.existsSync(path.join(process.cwd(), 'dist-templates', 'codex', 'agents')), '[9.5] dist-templates/codex/agents exists');
90
+ console.log('[9.5] dist-templates scaffolding present ✓');
91
+ }
92
+ finally {
93
+ fs.rmSync(tmp, { recursive: true, force: true });
94
+ }
95
+ console.log('TEST_HOST_INSTALLERS_GEMINI_CODEX_OK');
@@ -0,0 +1,295 @@
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.4 — HostInstaller uninstall regression test.
38
+ *
39
+ * Asserts:
40
+ * 1. Install then uninstall — every Story-3.3 artifact (5 agents, 4 commands, MCP snippet) is removed
41
+ * 2. Re-uninstall is idempotent — all actions are 'skipped-not-found'
42
+ * 3. User-edit preservation via .bak — install → user edits → reinstall (creates .bak) → uninstall
43
+ * restores the user's edit by renaming .bak back over the destination (NOT deleted)
44
+ * 4. Untouched user files — files in .claude/agents/ without the openlife- prefix survive
45
+ * 5. uninstallForGeminiCli throws HostNotYetSupportedError
46
+ * 6. uninstallForCodex throws HostNotYetSupportedError
47
+ * 7. Dispatcher uninstall('claude-code', ...) works and rejects unsupported hosts
48
+ * 8. CLI command `openlife system uninstall --host claude-code` is wired and prints JSON
49
+ */
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
52
+ const os = __importStar(require("os"));
53
+ const child_process_1 = require("child_process");
54
+ const HostInstaller_1 = require("./cli/HostInstaller");
55
+ function assert(cond, msg) {
56
+ if (!cond)
57
+ throw new Error(`ASSERTION_FAILED: ${msg}`);
58
+ }
59
+ function mkTemp(prefix = 'openlife-hostuninstaller-test-') {
60
+ return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
61
+ }
62
+ const EXPECTED_AGENTS = [
63
+ 'openlife-maestro.md',
64
+ 'openlife-lyra.md',
65
+ 'openlife-forge.md',
66
+ 'openlife-atlas.md',
67
+ 'openlife-genesis.md'
68
+ ];
69
+ const EXPECTED_COMMANDS = ['status.md', 'ask.md', 'doctor.md', 'dream.md'];
70
+ function testUninstallRemovesAllInstalledArtifacts() {
71
+ const tempRoot = mkTemp();
72
+ try {
73
+ const installer = new HostInstaller_1.HostInstaller();
74
+ installer.installForClaudeCode({ targetRoot: tempRoot });
75
+ // Sanity: install really put the files there.
76
+ for (const agent of EXPECTED_AGENTS) {
77
+ assert(fs.existsSync(path.join(tempRoot, '.claude', 'agents', agent)), `precondition: ${agent} should exist after install`);
78
+ }
79
+ const result = installer.uninstallForClaudeCode({ targetRoot: tempRoot });
80
+ assert(result.host === 'claude-code', `host should be claude-code; got ${result.host}`);
81
+ assert(result.targetRoot === tempRoot, 'targetRoot should round-trip');
82
+ assert(Array.isArray(result.files) && result.files.length > 0, 'files[] should be populated');
83
+ // Every agent file should be gone.
84
+ for (const agent of EXPECTED_AGENTS) {
85
+ const dst = path.join(tempRoot, '.claude', 'agents', agent);
86
+ assert(!fs.existsSync(dst), `agent should be removed: ${dst}`);
87
+ }
88
+ // Every command file should be gone.
89
+ for (const cmd of EXPECTED_COMMANDS) {
90
+ const dst = path.join(tempRoot, '.claude', 'commands', 'openlife', cmd);
91
+ assert(!fs.existsSync(dst), `command should be removed: ${dst}`);
92
+ }
93
+ // MCP snippet gone.
94
+ const mcpDst = path.join(tempRoot, '.openlife', 'install-mcp-snippet.json');
95
+ assert(!fs.existsSync(mcpDst), `mcp snippet should be removed: ${mcpDst}`);
96
+ // .openlife/ itself MUST survive (runtime state).
97
+ const stateDir = path.join(tempRoot, '.openlife');
98
+ assert(fs.existsSync(stateDir), '.openlife/ runtime state directory must NOT be removed');
99
+ // The openlife/ commands namespace directory should be removed (it was all ours and is now empty).
100
+ const cmdsNs = path.join(tempRoot, '.claude', 'commands', 'openlife');
101
+ assert(!fs.existsSync(cmdsNs), `empty openlife/ commands namespace should be removed: ${cmdsNs}`);
102
+ // Counted: 5 agents + 4 commands + 1 mcp snippet = 10 removals.
103
+ const removed = result.files.filter((f) => f.action === 'removed').length;
104
+ assert(removed === 10, `expected 10 'removed' actions (5 agents + 4 commands + 1 mcp); got ${removed}: ` +
105
+ JSON.stringify(result.files.map((f) => `${path.basename(f.destination)}:${f.action}`)));
106
+ }
107
+ finally {
108
+ fs.rmSync(tempRoot, { recursive: true, force: true });
109
+ }
110
+ }
111
+ function testIdempotentReUninstall() {
112
+ const tempRoot = mkTemp();
113
+ try {
114
+ const installer = new HostInstaller_1.HostInstaller();
115
+ installer.installForClaudeCode({ targetRoot: tempRoot });
116
+ installer.uninstallForClaudeCode({ targetRoot: tempRoot });
117
+ const second = installer.uninstallForClaudeCode({ targetRoot: tempRoot });
118
+ // On the second uninstall, everything should be 'skipped-not-found'.
119
+ const skipped = second.files.filter((f) => f.action === 'skipped-not-found').length;
120
+ assert(skipped === second.files.length, `all actions should be 'skipped-not-found' on re-uninstall; got ${skipped}/${second.files.length}: ` +
121
+ JSON.stringify(second.files.map((f) => f.action)));
122
+ }
123
+ finally {
124
+ fs.rmSync(tempRoot, { recursive: true, force: true });
125
+ }
126
+ }
127
+ function testUserEditPreservedViaBakRestore() {
128
+ const tempRoot = mkTemp();
129
+ try {
130
+ const installer = new HostInstaller_1.HostInstaller();
131
+ installer.installForClaudeCode({ targetRoot: tempRoot });
132
+ // User edits the agent. Then reinstalling will move the edit to .bak and overwrite.
133
+ const target = path.join(tempRoot, '.claude', 'agents', 'openlife-maestro.md');
134
+ const userEditContent = '# user-edited content — must survive uninstall\n';
135
+ fs.writeFileSync(target, userEditContent, 'utf-8');
136
+ const second = installer.installForClaudeCode({ targetRoot: tempRoot });
137
+ const updateAction = second.files.find((f) => f.destination === target);
138
+ assert(updateAction !== undefined && updateAction.action === 'updated', `precondition: reinstall after user-edit should report 'updated'; got ${JSON.stringify(updateAction)}`);
139
+ const bakPath = `${target}.bak`;
140
+ assert(fs.existsSync(bakPath), `precondition: .bak should exist at ${bakPath}`);
141
+ // Uninstall — .bak should be renamed back over the destination; user's edit survives.
142
+ const result = installer.uninstallForClaudeCode({ targetRoot: tempRoot });
143
+ const restoredAction = result.files.find((f) => f.destination === target);
144
+ assert(restoredAction !== undefined, `expected an action for ${target} in uninstall result`);
145
+ assert(restoredAction.action === 'restored-from-bak', `expected 'restored-from-bak'; got '${restoredAction.action}'`);
146
+ assert(restoredAction.backupPath === bakPath, `restoredAction.backupPath should be ${bakPath}; got ${restoredAction.backupPath}`);
147
+ // The destination must exist again WITH the user's content.
148
+ assert(fs.existsSync(target), `restored file should exist at ${target}`);
149
+ const finalContent = fs.readFileSync(target, 'utf-8');
150
+ assert(finalContent === userEditContent, `user's edit must survive uninstall; got: ${JSON.stringify(finalContent)}`);
151
+ // And the .bak should be gone (it was renamed, not deleted).
152
+ assert(!fs.existsSync(bakPath), `.bak should be consumed by rename; still present at ${bakPath}`);
153
+ }
154
+ finally {
155
+ fs.rmSync(tempRoot, { recursive: true, force: true });
156
+ }
157
+ }
158
+ function testUntouchedUserFilesSurvive() {
159
+ const tempRoot = mkTemp();
160
+ try {
161
+ const installer = new HostInstaller_1.HostInstaller();
162
+ installer.installForClaudeCode({ targetRoot: tempRoot });
163
+ // Drop a user-owned file (no openlife- prefix) in .claude/agents/.
164
+ const userFile = path.join(tempRoot, '.claude', 'agents', 'user-custom.md');
165
+ fs.writeFileSync(userFile, '# my custom agent — leave me alone\n', 'utf-8');
166
+ installer.uninstallForClaudeCode({ targetRoot: tempRoot });
167
+ assert(fs.existsSync(userFile), `user-owned file MUST NOT be removed: ${userFile}`);
168
+ const content = fs.readFileSync(userFile, 'utf-8');
169
+ assert(content === '# my custom agent — leave me alone\n', `user file content must be untouched; got: ${JSON.stringify(content)}`);
170
+ // And the parent .claude/agents/ should still exist because it contains user-custom.md.
171
+ assert(fs.existsSync(path.join(tempRoot, '.claude', 'agents')), '.claude/agents/ should survive if it still contains user files');
172
+ }
173
+ finally {
174
+ fs.rmSync(tempRoot, { recursive: true, force: true });
175
+ }
176
+ }
177
+ function testGeminiCliUninstallReversible() {
178
+ // Sprint 2 / Story 9.3 — gemini-cli uninstall is now a real reversible
179
+ // operation. The detailed coverage lives in
180
+ // test_host_installers_gemini_codex.ts; here we just assert it no longer
181
+ // throws HostNotYetSupportedError.
182
+ const tempRoot = mkTemp();
183
+ try {
184
+ const installer = new HostInstaller_1.HostInstaller();
185
+ installer.installForGeminiCli({ targetRoot: tempRoot });
186
+ let caught = null;
187
+ try {
188
+ installer.uninstallForGeminiCli({ targetRoot: tempRoot });
189
+ }
190
+ catch (err) {
191
+ caught = err;
192
+ }
193
+ assert(!(caught instanceof HostInstaller_1.HostNotYetSupportedError), 'gemini-cli uninstall should not throw HostNotYetSupportedError (Story 9.3)');
194
+ }
195
+ finally {
196
+ fs.rmSync(tempRoot, { recursive: true, force: true });
197
+ }
198
+ }
199
+ function testCodexUninstallReversible() {
200
+ // Mirror of the gemini-cli check above (Story 9.4).
201
+ const tempRoot = mkTemp();
202
+ try {
203
+ const installer = new HostInstaller_1.HostInstaller();
204
+ installer.installForCodex({ targetRoot: tempRoot });
205
+ let caught = null;
206
+ try {
207
+ installer.uninstallForCodex({ targetRoot: tempRoot });
208
+ }
209
+ catch (err) {
210
+ caught = err;
211
+ }
212
+ assert(!(caught instanceof HostInstaller_1.HostNotYetSupportedError), 'codex uninstall should not throw HostNotYetSupportedError (Story 9.4)');
213
+ }
214
+ finally {
215
+ fs.rmSync(tempRoot, { recursive: true, force: true });
216
+ }
217
+ }
218
+ function testDispatcherUninstallDispatchesClaudeCode() {
219
+ const tempRoot = mkTemp();
220
+ try {
221
+ const installer = new HostInstaller_1.HostInstaller();
222
+ installer.install('claude-code', { targetRoot: tempRoot });
223
+ const result = installer.uninstall('claude-code', { targetRoot: tempRoot });
224
+ assert(result.host === 'claude-code', `dispatcher should produce claude-code result; got ${result.host}`);
225
+ assert(!fs.existsSync(path.join(tempRoot, '.claude', 'agents', 'openlife-maestro.md')), 'dispatcher should have removed agent files');
226
+ // Sprint 2 / Stories 9.3 + 9.4 — dispatcher delegates uninstall to real
227
+ // implementations for gemini-cli and codex. We install + uninstall a
228
+ // fresh tempRoot to verify the dispatcher does not throw.
229
+ const gtempRoot = mkTemp();
230
+ try {
231
+ installer.installForGeminiCli({ targetRoot: gtempRoot });
232
+ const geminiResult = installer.uninstall('gemini-cli', { targetRoot: gtempRoot });
233
+ assert(geminiResult.host === 'gemini-cli', `dispatcher should produce gemini-cli uninstall result; got ${geminiResult.host}`);
234
+ }
235
+ finally {
236
+ fs.rmSync(gtempRoot, { recursive: true, force: true });
237
+ }
238
+ const ctempRoot = mkTemp();
239
+ try {
240
+ installer.installForCodex({ targetRoot: ctempRoot });
241
+ const codexResult = installer.uninstall('codex', { targetRoot: ctempRoot });
242
+ assert(codexResult.host === 'codex', `dispatcher should produce codex uninstall result; got ${codexResult.host}`);
243
+ }
244
+ finally {
245
+ fs.rmSync(ctempRoot, { recursive: true, force: true });
246
+ }
247
+ }
248
+ finally {
249
+ fs.rmSync(tempRoot, { recursive: true, force: true });
250
+ }
251
+ }
252
+ function testCliCommandWired() {
253
+ // Spawn the CLI in a temp dir as cwd, after installing into it.
254
+ // We DO NOT rely on end-to-end correctness here — unit tests above cover that. This test
255
+ // only verifies the command is registered and prints a parseable JSON envelope.
256
+ const tempRoot = mkTemp();
257
+ try {
258
+ const installer = new HostInstaller_1.HostInstaller();
259
+ installer.installForClaudeCode({ targetRoot: tempRoot });
260
+ const distIndex = path.resolve(__dirname, 'index.js');
261
+ assert(fs.existsSync(distIndex), `precondition: ${distIndex} must exist (run npm run build)`);
262
+ const proc = (0, child_process_1.spawnSync)(process.execPath, [distIndex, 'system', 'uninstall', '--host', 'claude-code'], { cwd: tempRoot, encoding: 'utf-8', timeout: 30000 });
263
+ assert(proc.status === 0, `CLI exit code should be 0; got ${proc.status}. stderr: ${proc.stderr}`);
264
+ // stdout should be valid JSON with ok:true.
265
+ const stdout = proc.stdout || '';
266
+ let parsed;
267
+ try {
268
+ parsed = JSON.parse(stdout);
269
+ }
270
+ catch (e) {
271
+ throw new Error(`CLI stdout should be JSON; got: ${stdout.slice(0, 400)}`);
272
+ }
273
+ assert(parsed.ok === true, `JSON should have ok:true; got: ${JSON.stringify(parsed).slice(0, 200)}`);
274
+ assert(parsed.host === 'claude-code', `JSON.host should be claude-code; got ${parsed.host}`);
275
+ assert(Array.isArray(parsed.files), 'JSON.files should be an array');
276
+ }
277
+ finally {
278
+ fs.rmSync(tempRoot, { recursive: true, force: true });
279
+ }
280
+ }
281
+ async function main() {
282
+ testUninstallRemovesAllInstalledArtifacts();
283
+ testIdempotentReUninstall();
284
+ testUserEditPreservedViaBakRestore();
285
+ testUntouchedUserFilesSurvive();
286
+ testGeminiCliUninstallReversible();
287
+ testCodexUninstallReversible();
288
+ testDispatcherUninstallDispatchesClaudeCode();
289
+ testCliCommandWired();
290
+ console.log('TEST_HOST_UNINSTALLER_OK');
291
+ }
292
+ main().catch((err) => {
293
+ console.error('TEST_HOST_UNINSTALLER_FAIL:', err?.message || err);
294
+ process.exit(1);
295
+ });