@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,240 @@
1
+ "use strict";
2
+ /**
3
+ * test_workflow_e2e — Story 4.5 regression suite.
4
+ *
5
+ * Spawns `node bin/openlife.js workflow ...` as a real child process
6
+ * against fresh temp project roots. Asserts the CLI surface introduced
7
+ * by Story 4.3 + the 4 ported workflows from Story 4.4 work end-to-end:
8
+ *
9
+ * 1. `workflow list` — JSON envelope, count=4
10
+ * 2. `workflow validate <each ported file>` — ok:true for all 4
11
+ * 3. `workflow run <file>` against the simulated executor — exits 0,
12
+ * state file created under <tmp>/.openlife/workflows/<runId>.json
13
+ * 4. `workflow status <runId>` — reads back the persisted state
14
+ * 5. `workflow abort <runId>` — idempotent, exits 0 (or matches state)
15
+ * 6. `workflow validate <invalid-yaml-fixture>` — exits 1 with error
16
+ * envelope listing workflow_invalid_yaml or similar code
17
+ *
18
+ * Prints TEST_WORKFLOW_E2E_OK on full pass.
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ const child_process_1 = require("child_process");
55
+ const fs = __importStar(require("fs"));
56
+ const os = __importStar(require("os"));
57
+ const path = __importStar(require("path"));
58
+ const REPO_ROOT = path.resolve(__dirname, '..');
59
+ const CLI = path.join(REPO_ROOT, 'bin', 'openlife.js');
60
+ const TIMEOUT_MS = 60_000;
61
+ function assert(cond, msg) {
62
+ if (!cond)
63
+ throw new Error(`assertion failed: ${msg}`);
64
+ }
65
+ function mkTmp() {
66
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'wf-e2e-'));
67
+ }
68
+ function rmTmp(dir) {
69
+ try {
70
+ fs.rmSync(dir, { recursive: true, force: true });
71
+ }
72
+ catch { /* ignore */ }
73
+ }
74
+ function run(args, cwd) {
75
+ return (0, child_process_1.spawnSync)(process.execPath, [CLI, ...args], {
76
+ cwd,
77
+ encoding: 'utf-8',
78
+ timeout: TIMEOUT_MS,
79
+ env: { ...process.env, OPENLIFE_STATE_DIR: path.join(cwd, '.openlife') },
80
+ });
81
+ }
82
+ function extractJson(stdout) {
83
+ // Prefer the largest balanced top-level JSON block in stdout (handles
84
+ // logs/warnings preceding the envelope).
85
+ let best = null;
86
+ let depth = 0;
87
+ let start = -1;
88
+ for (let i = 0; i < stdout.length; i++) {
89
+ const ch = stdout[i];
90
+ if (ch === '{') {
91
+ if (depth === 0)
92
+ start = i;
93
+ depth += 1;
94
+ }
95
+ else if (ch === '}') {
96
+ depth -= 1;
97
+ if (depth === 0 && start >= 0) {
98
+ const block = { start, end: i + 1 };
99
+ if (!best || (block.end - block.start) > (best.end - best.start))
100
+ best = block;
101
+ start = -1;
102
+ }
103
+ }
104
+ }
105
+ if (!best)
106
+ throw new Error(`no JSON object found in stdout: ${stdout.slice(0, 200)}`);
107
+ return JSON.parse(stdout.slice(best.start, best.end));
108
+ }
109
+ // ─────────────────────────────────────────────────────────────
110
+ // Scenario 1 — `workflow list`
111
+ // ─────────────────────────────────────────────────────────────
112
+ function scenarioList() {
113
+ const tmp = mkTmp();
114
+ try {
115
+ const r = run(['workflow', 'list'], tmp);
116
+ assert(r.status === 0, `list exit code: ${r.status}, stderr: ${r.stderr}`);
117
+ const obj = extractJson(r.stdout);
118
+ assert(obj.ok === true, 'list must return ok:true');
119
+ assert(obj.count === 4, `expected 4 workflows, got ${obj.count}`);
120
+ const ids = obj.workflows.map((w) => w.id).sort();
121
+ assert(JSON.stringify(ids) === JSON.stringify(['brownfield-discovery', 'greenfield-fullstack', 'qa-loop', 'story-development-cycle']), `unexpected workflow ids: ${ids.join(', ')}`);
122
+ console.log('✅ scenario 1: workflow list (4 workflows)');
123
+ }
124
+ finally {
125
+ rmTmp(tmp);
126
+ }
127
+ }
128
+ // ─────────────────────────────────────────────────────────────
129
+ // Scenario 2 — `workflow validate <each>`
130
+ // ─────────────────────────────────────────────────────────────
131
+ function scenarioValidateEach() {
132
+ const tmp = mkTmp();
133
+ const files = [
134
+ 'dist-templates/workflows/story-development-cycle.yaml',
135
+ 'dist-templates/workflows/greenfield-fullstack.yaml',
136
+ 'dist-templates/workflows/brownfield-discovery.yaml',
137
+ 'dist-templates/workflows/qa-loop.yaml',
138
+ ];
139
+ try {
140
+ for (const f of files) {
141
+ const full = path.join(REPO_ROOT, f);
142
+ const r = run(['workflow', 'validate', full], tmp);
143
+ assert(r.status === 0, `validate ${f} exit: ${r.status}, stderr: ${r.stderr}`);
144
+ const obj = extractJson(r.stdout);
145
+ assert(obj.ok === true, `validate ${f} must return ok:true`);
146
+ assert(typeof obj.workflowId === 'string' && obj.workflowId.length > 0, `validate ${f} must include workflowId`);
147
+ }
148
+ console.log('✅ scenario 2: validate all 4 ported workflows');
149
+ }
150
+ finally {
151
+ rmTmp(tmp);
152
+ }
153
+ }
154
+ // ─────────────────────────────────────────────────────────────
155
+ // Scenario 3 — `workflow run <file>` (simulated)
156
+ // ─────────────────────────────────────────────────────────────
157
+ function scenarioRun() {
158
+ const tmp = mkTmp();
159
+ const file = path.join(REPO_ROOT, 'dist-templates/workflows/story-development-cycle.yaml');
160
+ const r = run(['workflow', 'run', file], tmp);
161
+ assert(r.status === 0, `run exit: ${r.status}, stderr: ${r.stderr}`);
162
+ const obj = extractJson(r.stdout);
163
+ assert(obj.ok === true, 'run must return ok:true (status completed)');
164
+ assert(obj.state.status === 'completed', `expected status=completed, got ${obj.state.status}`);
165
+ assert(obj.state.completedSteps.length === 4, `expected 4 completed steps, got ${obj.state.completedSteps.length}`);
166
+ // state file on disk
167
+ const stateFile = path.join(tmp, '.openlife', 'workflows', `${obj.state.runId}.json`);
168
+ assert(fs.existsSync(stateFile), `state file must exist at ${stateFile}`);
169
+ console.log('✅ scenario 3: workflow run (simulated executor, 4 steps completed)');
170
+ return { runId: obj.state.runId, tmpRoot: tmp };
171
+ }
172
+ // ─────────────────────────────────────────────────────────────
173
+ // Scenario 4 — `workflow status <runId>`
174
+ // ─────────────────────────────────────────────────────────────
175
+ function scenarioStatus(runId, tmpRoot) {
176
+ const r = run(['workflow', 'status', runId], tmpRoot);
177
+ assert(r.status === 0, `status exit: ${r.status}, stderr: ${r.stderr}`);
178
+ const obj = extractJson(r.stdout);
179
+ assert(obj.ok === true, 'status must return ok:true for known runId');
180
+ assert(obj.state.runId === runId, 'runId round-trip');
181
+ assert(obj.state.status === 'completed', 'persisted state must reflect completion');
182
+ console.log('✅ scenario 4: workflow status (persisted state round-trip)');
183
+ }
184
+ // ─────────────────────────────────────────────────────────────
185
+ // Scenario 5 — `workflow abort <runId>` against completed (no-op)
186
+ // ─────────────────────────────────────────────────────────────
187
+ function scenarioAbortIdempotent(runId, tmpRoot) {
188
+ const r = run(['workflow', 'abort', runId], tmpRoot);
189
+ assert(r.status === 0, `abort exit: ${r.status}, stderr: ${r.stderr}`);
190
+ const obj = extractJson(r.stdout);
191
+ assert(obj.ok === true, 'abort must return ok:true');
192
+ // Already terminal (completed) — abort leaves it as completed (no transition)
193
+ assert(obj.state.status === 'completed', `abort on terminal must keep status, got ${obj.state.status}`);
194
+ console.log('✅ scenario 5: workflow abort idempotent on terminal run');
195
+ }
196
+ // ─────────────────────────────────────────────────────────────
197
+ // Scenario 6 — validate invalid YAML fixture
198
+ // ─────────────────────────────────────────────────────────────
199
+ function scenarioInvalidValidate() {
200
+ const tmp = mkTmp();
201
+ try {
202
+ const bad = path.join(tmp, 'bad.yaml');
203
+ fs.writeFileSync(bad, 'just: a string\nnot: a workflow\n', 'utf-8');
204
+ const r = run(['workflow', 'validate', bad], tmp);
205
+ assert(r.status === 1, `invalid validate must exit 1, got ${r.status}`);
206
+ const obj = extractJson(r.stdout);
207
+ assert(obj.ok === false, 'invalid validate must return ok:false');
208
+ assert(obj.errors.some((e) => e.code === 'workflow_missing_root'), `expected workflow_missing_root error, got ${obj.errors.map((e) => e.code).join(',')}`);
209
+ console.log('✅ scenario 6: validate invalid YAML (missing `workflow:` root)');
210
+ }
211
+ finally {
212
+ rmTmp(tmp);
213
+ }
214
+ }
215
+ // ─────────────────────────────────────────────────────────────
216
+ // Driver
217
+ // ─────────────────────────────────────────────────────────────
218
+ function main() {
219
+ console.log('🧪 test_workflow_e2e — Story 4.5 regression suite');
220
+ scenarioList();
221
+ scenarioValidateEach();
222
+ const { runId, tmpRoot } = scenarioRun();
223
+ try {
224
+ scenarioStatus(runId, tmpRoot);
225
+ scenarioAbortIdempotent(runId, tmpRoot);
226
+ }
227
+ finally {
228
+ rmTmp(tmpRoot);
229
+ }
230
+ scenarioInvalidValidate();
231
+ console.log('');
232
+ console.log('TEST_WORKFLOW_E2E_OK');
233
+ }
234
+ try {
235
+ main();
236
+ }
237
+ catch (err) {
238
+ console.error('❌ test_workflow_e2e FAILED:', err instanceof Error ? err.message : err);
239
+ process.exit(1);
240
+ }
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ /**
3
+ * test_workflow_engine — Story 4.2 regression suite.
4
+ *
5
+ * Asserts the WorkflowEngine contract via 6 scenarios:
6
+ * 1. Happy path — workflow with 4 sequential executable steps + phase
7
+ * markers runs to `completed` with all steps marked, artifacts
8
+ * accumulated, checkpoint cleared at the end.
9
+ * 2. Elicit pause — step with elicit:true sets run status to
10
+ * `awaiting_input`; provideInput() resumes the run to completion.
11
+ * 3. Resume after simulated crash — run halted by injected executor
12
+ * failure on step 3 is resumable; subsequent resume() with a
13
+ * passing executor finishes all remaining steps.
14
+ * 4. Abort during run — abort() sets status=aborted and clears the
15
+ * checkpoint; idempotent on re-abort.
16
+ * 5. Optional + condition — optional step whose condition is not met
17
+ * in context is `skipped`, not `completed`; runs around it succeed.
18
+ * 6. Status / state file durability — status(runId) returns null for
19
+ * unknown ids; state file lives under <stateDir>/workflows/.
20
+ *
21
+ * Prints TEST_WORKFLOW_ENGINE_OK on full pass.
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ const fs = __importStar(require("fs"));
58
+ const os = __importStar(require("os"));
59
+ const path = __importStar(require("path"));
60
+ const WorkflowEngine_1 = require("./orchestrator/workflow/WorkflowEngine");
61
+ function assert(cond, msg) {
62
+ if (!cond)
63
+ throw new Error(`assertion failed: ${msg}`);
64
+ }
65
+ function mkTmp() {
66
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'wf-engine-test-'));
67
+ }
68
+ function rmTmp(dir) {
69
+ try {
70
+ fs.rmSync(dir, { recursive: true, force: true });
71
+ }
72
+ catch { /* ignore */ }
73
+ }
74
+ function makeWorkflow(extra = {}) {
75
+ return {
76
+ id: 'test-wf',
77
+ name: 'Test',
78
+ type: 'custom',
79
+ version: '1.0',
80
+ sequence: [
81
+ { phase: 0, name: 'Setup' },
82
+ { id: 's1', agent: 'dev', action: 'do-a', creates: ['a.md'] },
83
+ { id: 's2', agent: 'dev', action: 'do-b', creates: ['b.md'], requires: 's1' },
84
+ { phase: 1, name: 'Cleanup' },
85
+ { id: 's3', agent: 'dev', action: 'do-c', creates: ['c.md'], requires: 's2' },
86
+ { id: 's4', agent: 'dev', action: 'do-d', updates: ['c.md'], requires: 's3' },
87
+ ],
88
+ ...extra,
89
+ };
90
+ }
91
+ class ScriptedExecutor {
92
+ rules;
93
+ constructor(rules) {
94
+ this.rules = rules;
95
+ }
96
+ async execute(inv) {
97
+ const r = this.rules[inv.step.id];
98
+ if (!r) {
99
+ const artifacts = [];
100
+ if (Array.isArray(inv.step.creates))
101
+ artifacts.push(...inv.step.creates);
102
+ if (Array.isArray(inv.step.updates))
103
+ artifacts.push(...inv.step.updates);
104
+ return { status: 'completed', artifacts, result: 'default' };
105
+ }
106
+ return r;
107
+ }
108
+ }
109
+ // ─────────────────────────────────────────────────────────────
110
+ // Scenario 1 — happy path
111
+ // ─────────────────────────────────────────────────────────────
112
+ async function scenarioHappyPath() {
113
+ const tmp = mkTmp();
114
+ const prev = process.env.OPENLIFE_STATE_DIR;
115
+ try {
116
+ process.env.OPENLIFE_STATE_DIR = path.join(tmp, '.openlife');
117
+ const engine = new WorkflowEngine_1.WorkflowEngine();
118
+ const wf = makeWorkflow();
119
+ const state = await engine.run(wf);
120
+ assert(state.status === 'completed', `expected completed, got ${state.status}`);
121
+ assert(state.completedSteps.length === 4, `expected 4 completed, got ${state.completedSteps.length}`);
122
+ assert(state.artifacts.includes('a.md') && state.artifacts.includes('c.md'), 'artifacts must accumulate');
123
+ // state file written
124
+ const stateFile = path.join(engine._stateDir(), 'workflows', `${state.runId}.json`);
125
+ assert(fs.existsSync(stateFile), 'state file must exist');
126
+ // events log written
127
+ const eventsFile = path.join(engine._stateDir(), 'workflows', 'events', `${state.runId}.jsonl`);
128
+ assert(fs.existsSync(eventsFile), 'events log must exist');
129
+ const events = fs.readFileSync(eventsFile, 'utf-8').split('\n').filter((l) => l.length > 0);
130
+ assert(events.length >= 6, `expected at least 6 events (run.started + 4 step + run.completed), got ${events.length}`);
131
+ console.log('✅ scenario 1: happy path');
132
+ }
133
+ finally {
134
+ if (prev === undefined)
135
+ delete process.env.OPENLIFE_STATE_DIR;
136
+ else
137
+ process.env.OPENLIFE_STATE_DIR = prev;
138
+ rmTmp(tmp);
139
+ }
140
+ }
141
+ // ─────────────────────────────────────────────────────────────
142
+ // Scenario 2 — elicit pause + provideInput resumes
143
+ // ─────────────────────────────────────────────────────────────
144
+ async function scenarioElicit() {
145
+ const tmp = mkTmp();
146
+ const prev = process.env.OPENLIFE_STATE_DIR;
147
+ try {
148
+ process.env.OPENLIFE_STATE_DIR = path.join(tmp, '.openlife');
149
+ const engine = new WorkflowEngine_1.WorkflowEngine();
150
+ const wf = {
151
+ id: 'elicit-wf',
152
+ name: 'Elicit',
153
+ type: 'custom',
154
+ version: '1.0',
155
+ sequence: [
156
+ { id: 'a', agent: 'dev' },
157
+ { id: 'gate', agent: 'pm', elicit: true },
158
+ { id: 'b', agent: 'dev' },
159
+ ],
160
+ };
161
+ const state = await engine.run(wf);
162
+ assert(state.status === 'awaiting_input', `expected awaiting_input, got ${state.status}`);
163
+ assert(state.currentStep === 'gate', `expected currentStep=gate, got ${state.currentStep ?? 'none'}`);
164
+ assert(state.completedSteps.length === 1, 'only `a` should be done before elicit');
165
+ const resumed = await engine.provideInput(wf, state.runId, 'gate', { answer: 'yes' });
166
+ assert(resumed.status === 'completed', `expected completed after provideInput, got ${resumed.status}`);
167
+ assert(resumed.completedSteps.length === 3, `expected 3 completed, got ${resumed.completedSteps.length}`);
168
+ console.log('✅ scenario 2: elicit pause + provideInput');
169
+ }
170
+ finally {
171
+ if (prev === undefined)
172
+ delete process.env.OPENLIFE_STATE_DIR;
173
+ else
174
+ process.env.OPENLIFE_STATE_DIR = prev;
175
+ rmTmp(tmp);
176
+ }
177
+ }
178
+ // ─────────────────────────────────────────────────────────────
179
+ // Scenario 3 — resume after injected step failure
180
+ // ─────────────────────────────────────────────────────────────
181
+ async function scenarioResume() {
182
+ const tmp = mkTmp();
183
+ const prev = process.env.OPENLIFE_STATE_DIR;
184
+ try {
185
+ process.env.OPENLIFE_STATE_DIR = path.join(tmp, '.openlife');
186
+ // First run: executor fails on step 3
187
+ const failing = new WorkflowEngine_1.WorkflowEngine({
188
+ executor: new ScriptedExecutor({
189
+ s3: { status: 'failed', error: 'simulated network drop' },
190
+ }),
191
+ });
192
+ const wf = makeWorkflow();
193
+ const first = await failing.run(wf);
194
+ assert(first.status === 'failed', `expected failed, got ${first.status}`);
195
+ assert(first.completedSteps.length === 2, `expected 2 done before failure, got ${first.completedSteps.length}`);
196
+ // Mark as recoverable by flipping status back to running (in real life
197
+ // a resume would happen after process restart; we simulate by setting
198
+ // status to running and re-invoking resume with a passing executor).
199
+ // resume() expects non-terminal status; we mutate state for the test.
200
+ const stateFile = path.join(failing._stateDir(), 'workflows', `${first.runId}.json`);
201
+ const raw = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
202
+ raw.status = 'running';
203
+ raw.failureReason = undefined;
204
+ raw.completedAt = undefined;
205
+ fs.writeFileSync(stateFile, JSON.stringify(raw, null, 2));
206
+ // Resume with passing executor
207
+ const passing = new WorkflowEngine_1.WorkflowEngine({ executor: new ScriptedExecutor({}) });
208
+ const resumed = await passing.resume(wf, first.runId);
209
+ assert(resumed.status === 'completed', `expected completed on resume, got ${resumed.status}`);
210
+ assert(resumed.completedSteps.length === 4, `expected 4 done after resume, got ${resumed.completedSteps.length}`);
211
+ assert(resumed.completedSteps.includes('s3'), 'resumed run must complete the previously-failed step');
212
+ console.log('✅ scenario 3: resume after injected failure');
213
+ }
214
+ finally {
215
+ if (prev === undefined)
216
+ delete process.env.OPENLIFE_STATE_DIR;
217
+ else
218
+ process.env.OPENLIFE_STATE_DIR = prev;
219
+ rmTmp(tmp);
220
+ }
221
+ }
222
+ // ─────────────────────────────────────────────────────────────
223
+ // Scenario 4 — abort
224
+ // ─────────────────────────────────────────────────────────────
225
+ async function scenarioAbort() {
226
+ const tmp = mkTmp();
227
+ const prev = process.env.OPENLIFE_STATE_DIR;
228
+ try {
229
+ process.env.OPENLIFE_STATE_DIR = path.join(tmp, '.openlife');
230
+ const engine = new WorkflowEngine_1.WorkflowEngine();
231
+ const wf = {
232
+ id: 'abort-wf',
233
+ name: 'Abort',
234
+ type: 'custom',
235
+ version: '1.0',
236
+ sequence: [
237
+ { id: 'a', agent: 'dev', elicit: true }, // pauses immediately
238
+ ],
239
+ };
240
+ const state = await engine.run(wf);
241
+ assert(state.status === 'awaiting_input', 'must pause on elicit');
242
+ const aborted = engine.abort(state.runId, 'test reason');
243
+ assert(aborted !== null && aborted.status === 'aborted', 'must mark as aborted');
244
+ assert(aborted.failureReason === 'test reason', 'reason must be recorded');
245
+ // Idempotent on second call
246
+ const again = engine.abort(state.runId, 'another reason');
247
+ assert(again?.status === 'aborted' && again.failureReason === 'test reason', 'abort must be idempotent (preserves first reason)');
248
+ console.log('✅ scenario 4: abort + idempotency');
249
+ }
250
+ finally {
251
+ if (prev === undefined)
252
+ delete process.env.OPENLIFE_STATE_DIR;
253
+ else
254
+ process.env.OPENLIFE_STATE_DIR = prev;
255
+ rmTmp(tmp);
256
+ }
257
+ }
258
+ // ─────────────────────────────────────────────────────────────
259
+ // Scenario 5 — optional + condition not met → skipped
260
+ // ─────────────────────────────────────────────────────────────
261
+ async function scenarioOptionalCondition() {
262
+ const tmp = mkTmp();
263
+ const prev = process.env.OPENLIFE_STATE_DIR;
264
+ try {
265
+ process.env.OPENLIFE_STATE_DIR = path.join(tmp, '.openlife');
266
+ const engine = new WorkflowEngine_1.WorkflowEngine();
267
+ const wf = {
268
+ id: 'cond-wf',
269
+ name: 'Cond',
270
+ type: 'custom',
271
+ version: '1.0',
272
+ sequence: [
273
+ { id: 'always', agent: 'dev' },
274
+ { id: 'maybe', agent: 'dev', optional: true, condition: 'feature_enabled' },
275
+ { id: 'always-2', agent: 'dev' },
276
+ ],
277
+ };
278
+ const state = await engine.run(wf, { other_flag: true });
279
+ assert(state.status === 'completed', `expected completed, got ${state.status}`);
280
+ assert(state.steps['maybe'].status === 'skipped', 'maybe must be skipped when condition unmet');
281
+ assert(state.steps['always'].status === 'completed', 'always must complete');
282
+ assert(state.steps['always-2'].status === 'completed', 'always-2 must complete');
283
+ console.log('✅ scenario 5: optional + condition (skipped when unmet)');
284
+ }
285
+ finally {
286
+ if (prev === undefined)
287
+ delete process.env.OPENLIFE_STATE_DIR;
288
+ else
289
+ process.env.OPENLIFE_STATE_DIR = prev;
290
+ rmTmp(tmp);
291
+ }
292
+ }
293
+ // ─────────────────────────────────────────────────────────────
294
+ // Scenario 6 — status() returns null for unknown id
295
+ // ─────────────────────────────────────────────────────────────
296
+ function scenarioStatusUnknown() {
297
+ const tmp = mkTmp();
298
+ const prev = process.env.OPENLIFE_STATE_DIR;
299
+ try {
300
+ process.env.OPENLIFE_STATE_DIR = path.join(tmp, '.openlife');
301
+ const engine = new WorkflowEngine_1.WorkflowEngine();
302
+ assert(engine.status('does-not-exist') === null, 'status must return null for unknown id');
303
+ console.log('✅ scenario 6: status(unknown) returns null');
304
+ }
305
+ finally {
306
+ if (prev === undefined)
307
+ delete process.env.OPENLIFE_STATE_DIR;
308
+ else
309
+ process.env.OPENLIFE_STATE_DIR = prev;
310
+ rmTmp(tmp);
311
+ }
312
+ }
313
+ // ─────────────────────────────────────────────────────────────
314
+ // Driver
315
+ // ─────────────────────────────────────────────────────────────
316
+ async function main() {
317
+ console.log('🧪 test_workflow_engine — Story 4.2 regression suite');
318
+ await scenarioHappyPath();
319
+ await scenarioElicit();
320
+ await scenarioResume();
321
+ await scenarioAbort();
322
+ await scenarioOptionalCondition();
323
+ scenarioStatusUnknown();
324
+ console.log('');
325
+ console.log('TEST_WORKFLOW_ENGINE_OK');
326
+ }
327
+ main().catch((err) => {
328
+ console.error('❌ test_workflow_engine FAILED:', err instanceof Error ? err.message : err);
329
+ process.exit(1);
330
+ });