@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,232 @@
1
+ "use strict";
2
+ /**
3
+ * ConditionParser — tiny boolean expression engine for workflow step
4
+ * conditions.
5
+ *
6
+ * Story 10.3 — OpenLife v1.4.
7
+ *
8
+ * Replaces the v1.2/v1.3 literal-only `conditionMet()` in WorkflowEngine.
9
+ *
10
+ * Grammar (precedence-climbing, lowest to highest):
11
+ * expr := orExpr
12
+ * orExpr := andExpr ( "OR" andExpr )*
13
+ * andExpr := notExpr ( "AND" notExpr )*
14
+ * notExpr := "NOT" notExpr | primary
15
+ * primary := "(" expr ")" | comparison | identifier
16
+ * comparison := identifier ( "==" | "!=" ) literal
17
+ * identifier := [A-Za-z_][A-Za-z0-9_.]*
18
+ * literal := number | "true" | "false" | "null" | quoted-string
19
+ *
20
+ * Backward-compat:
21
+ * A bare identifier `foo` evaluates to `ctx.foo === true` (same as v1.2).
22
+ *
23
+ * Never throws. On parse failure, evaluate() returns false and the
24
+ * `parse()` result carries the error.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.parseCondition = parseCondition;
28
+ exports.evaluate = evaluate;
29
+ exports.evaluateCondition = evaluateCondition;
30
+ function tokenize(input) {
31
+ const tokens = [];
32
+ let i = 0;
33
+ while (i < input.length) {
34
+ const c = input[i];
35
+ if (/\s/.test(c)) {
36
+ i++;
37
+ continue;
38
+ }
39
+ if (c === '(' || c === ')') {
40
+ tokens.push({ type: 'op', value: c });
41
+ i++;
42
+ continue;
43
+ }
44
+ if (c === '=' && input[i + 1] === '=') {
45
+ tokens.push({ type: 'op', value: '==' });
46
+ i += 2;
47
+ continue;
48
+ }
49
+ if (c === '!' && input[i + 1] === '=') {
50
+ tokens.push({ type: 'op', value: '!=' });
51
+ i += 2;
52
+ continue;
53
+ }
54
+ if (c === '"' || c === "'") {
55
+ const end = input.indexOf(c, i + 1);
56
+ if (end === -1)
57
+ return null; // unterminated
58
+ tokens.push({ type: 'string', value: input.slice(i + 1, end) });
59
+ i = end + 1;
60
+ continue;
61
+ }
62
+ if (/[0-9-]/.test(c)) {
63
+ const m = input.slice(i).match(/^-?\d+(?:\.\d+)?/);
64
+ if (m) {
65
+ tokens.push({ type: 'number', value: Number(m[0]) });
66
+ i += m[0].length;
67
+ continue;
68
+ }
69
+ }
70
+ if (/[A-Za-z_]/.test(c)) {
71
+ const m = input.slice(i).match(/^[A-Za-z_][A-Za-z0-9_.]*/);
72
+ if (m) {
73
+ const word = m[0];
74
+ if (word === 'AND')
75
+ tokens.push({ type: 'op', value: 'AND' });
76
+ else if (word === 'OR')
77
+ tokens.push({ type: 'op', value: 'OR' });
78
+ else if (word === 'NOT')
79
+ tokens.push({ type: 'op', value: 'NOT' });
80
+ else if (word === 'true')
81
+ tokens.push({ type: 'bool', value: true });
82
+ else if (word === 'false')
83
+ tokens.push({ type: 'bool', value: false });
84
+ else if (word === 'null')
85
+ tokens.push({ type: 'null' });
86
+ else
87
+ tokens.push({ type: 'ident', value: word });
88
+ i += word.length;
89
+ continue;
90
+ }
91
+ }
92
+ return null; // unknown char
93
+ }
94
+ return tokens;
95
+ }
96
+ // ─── Parser (recursive-descent, precedence-climbing) ────────
97
+ class Parser {
98
+ tokens;
99
+ pos = 0;
100
+ constructor(tokens) {
101
+ this.tokens = tokens;
102
+ }
103
+ parseTopLevel() {
104
+ const node = this.parseOr();
105
+ if (this.pos < this.tokens.length)
106
+ return null; // leftover tokens
107
+ return node;
108
+ }
109
+ peek() { return this.tokens[this.pos]; }
110
+ consume() { return this.tokens[this.pos++]; }
111
+ parseOr() {
112
+ let left = this.parseAnd();
113
+ if (!left)
114
+ return null;
115
+ while (this.peek()?.type === 'op' && this.peek().value === 'OR') {
116
+ this.consume();
117
+ const right = this.parseAnd();
118
+ if (!right)
119
+ return null;
120
+ left = { kind: 'or', left, right };
121
+ }
122
+ return left;
123
+ }
124
+ parseAnd() {
125
+ let left = this.parseNot();
126
+ if (!left)
127
+ return null;
128
+ while (this.peek()?.type === 'op' && this.peek().value === 'AND') {
129
+ this.consume();
130
+ const right = this.parseNot();
131
+ if (!right)
132
+ return null;
133
+ left = { kind: 'and', left, right };
134
+ }
135
+ return left;
136
+ }
137
+ parseNot() {
138
+ if (this.peek()?.type === 'op' && this.peek().value === 'NOT') {
139
+ this.consume();
140
+ const inner = this.parseNot();
141
+ if (!inner)
142
+ return null;
143
+ return { kind: 'not', inner };
144
+ }
145
+ return this.parsePrimary();
146
+ }
147
+ parsePrimary() {
148
+ const tok = this.peek();
149
+ if (!tok)
150
+ return null;
151
+ if (tok.type === 'op' && tok.value === '(') {
152
+ this.consume();
153
+ const inner = this.parseOr();
154
+ const close = this.consume();
155
+ if (!close || close.type !== 'op' || close.value !== ')')
156
+ return null;
157
+ return inner;
158
+ }
159
+ if (tok.type === 'ident') {
160
+ this.consume();
161
+ // Check for comparison operator
162
+ const next = this.peek();
163
+ if (next?.type === 'op' && (next.value === '==' || next.value === '!=')) {
164
+ const opTok = this.consume();
165
+ const litTok = this.consume();
166
+ if (!litTok)
167
+ return null;
168
+ let lit;
169
+ if (litTok.type === 'string')
170
+ lit = litTok.value;
171
+ else if (litTok.type === 'number')
172
+ lit = litTok.value;
173
+ else if (litTok.type === 'bool')
174
+ lit = litTok.value;
175
+ else if (litTok.type === 'null')
176
+ lit = null;
177
+ else
178
+ return null;
179
+ return { kind: opTok.value === '==' ? 'eq' : 'neq', ident: tok.value, literal: lit };
180
+ }
181
+ return { kind: 'truthy', ident: tok.value };
182
+ }
183
+ return null;
184
+ }
185
+ }
186
+ // ─── Public API ────────────────────────────────────────────
187
+ function parseCondition(input) {
188
+ const tokens = tokenize(input);
189
+ if (!tokens)
190
+ return { ok: false, error: 'tokenize_failed' };
191
+ if (tokens.length === 0)
192
+ return { ok: false, error: 'empty_expression' };
193
+ const ast = new Parser(tokens).parseTopLevel();
194
+ if (!ast)
195
+ return { ok: false, error: 'parse_failed' };
196
+ return { ok: true, ast };
197
+ }
198
+ /** Resolve `a.b.c` against a context object. Returns undefined on miss. */
199
+ function resolveIdent(ident, ctx) {
200
+ const parts = ident.split('.');
201
+ let cur = ctx;
202
+ for (const p of parts) {
203
+ if (cur === null || cur === undefined || typeof cur !== 'object')
204
+ return undefined;
205
+ cur = cur[p];
206
+ }
207
+ return cur;
208
+ }
209
+ function evaluate(ast, ctx) {
210
+ switch (ast.kind) {
211
+ case 'and': return evaluate(ast.left, ctx) && evaluate(ast.right, ctx);
212
+ case 'or': return evaluate(ast.left, ctx) || evaluate(ast.right, ctx);
213
+ case 'not': return !evaluate(ast.inner, ctx);
214
+ case 'truthy': return resolveIdent(ast.ident, ctx) === true;
215
+ case 'eq': return resolveIdent(ast.ident, ctx) === ast.literal;
216
+ case 'neq': return resolveIdent(ast.ident, ctx) !== ast.literal;
217
+ default: return false;
218
+ }
219
+ }
220
+ /**
221
+ * One-shot helper used by WorkflowEngine. Parses + evaluates in one call.
222
+ * Backwards-compatible: empty string returns true (no condition = pass).
223
+ * Parse failures return false (refuse to run if expression is broken).
224
+ */
225
+ function evaluateCondition(expr, ctx) {
226
+ if (!expr || expr.trim() === '')
227
+ return true;
228
+ const r = parseCondition(expr);
229
+ if (!r.ok || !r.ast)
230
+ return false;
231
+ return evaluate(r.ast, ctx);
232
+ }
@@ -0,0 +1,379 @@
1
+ "use strict";
2
+ /**
3
+ * WorkflowEngine — execute, checkpoint, resume, and abort workflow runs.
4
+ *
5
+ * Story 4.2 — OpenLife v1.2 Royal Stack.
6
+ *
7
+ * The engine is the maestro. It iterates the workflow `sequence`,
8
+ * dispatches each executable step through an injected
9
+ * `WorkflowStepExecutor` (default = Gatekeeper-backed), records
10
+ * progress to `.openlife/workflows/<runId>.json` via AtomicWriter,
11
+ * appends a step-level event log to `.openlife/workflows/events/
12
+ * <runId>.jsonl`, and saves a MissionCheckpoint after each successful
13
+ * step.
14
+ *
15
+ * Crash safety: every state transition is durable. If the daemon dies
16
+ * mid-step, calling `resume(runId)` reads the last checkpoint and
17
+ * continues from the next pending step (idempotent steps may re-execute
18
+ * once; non-idempotent are skipped to avoid double-side-effects).
19
+ *
20
+ * Elicit support: a step with `elicit: true` causes the engine to set
21
+ * run status to `awaiting_input` and return control. The caller must
22
+ * later invoke `provideInput(runId, stepId, payload)` to resume.
23
+ */
24
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ var desc = Object.getOwnPropertyDescriptor(m, k);
27
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
28
+ desc = { enumerable: true, get: function() { return m[k]; } };
29
+ }
30
+ Object.defineProperty(o, k2, desc);
31
+ }) : (function(o, m, k, k2) {
32
+ if (k2 === undefined) k2 = k;
33
+ o[k2] = m[k];
34
+ }));
35
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
36
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
37
+ }) : function(o, v) {
38
+ o["default"] = v;
39
+ });
40
+ var __importStar = (this && this.__importStar) || (function () {
41
+ var ownKeys = function(o) {
42
+ ownKeys = Object.getOwnPropertyNames || function (o) {
43
+ var ar = [];
44
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
45
+ return ar;
46
+ };
47
+ return ownKeys(o);
48
+ };
49
+ return function (mod) {
50
+ if (mod && mod.__esModule) return mod;
51
+ var result = {};
52
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
53
+ __setModuleDefault(result, mod);
54
+ return result;
55
+ };
56
+ })();
57
+ Object.defineProperty(exports, "__esModule", { value: true });
58
+ exports.WorkflowEngine = exports.SimulatedStepExecutor = void 0;
59
+ const crypto = __importStar(require("crypto"));
60
+ const fs = __importStar(require("fs"));
61
+ const path = __importStar(require("path"));
62
+ const ToolsetGuard_1 = require("../toolset/ToolsetGuard");
63
+ const WorkflowSchema_1 = require("./WorkflowSchema");
64
+ const AtomicWriter_1 = require("../util/AtomicWriter");
65
+ const MissionState_1 = require("../MissionState");
66
+ // ─────────────────────────────────────────────────────────────
67
+ // Default executor — simulated mode. Reports each step as completed
68
+ // without invoking real LLMs. Story 4.2 ships this as the v1.2
69
+ // minimum; deeper Gatekeeper integration is wired in Epic 5 once the
70
+ // AIOBuilder CLI commands materialize.
71
+ // ─────────────────────────────────────────────────────────────
72
+ class SimulatedStepExecutor {
73
+ // eslint-disable-next-line @typescript-eslint/require-await
74
+ async execute(inv) {
75
+ if (inv.step.elicit) {
76
+ return { status: 'awaiting_input' };
77
+ }
78
+ const artifacts = [];
79
+ if (Array.isArray(inv.step.creates))
80
+ artifacts.push(...inv.step.creates);
81
+ if (Array.isArray(inv.step.updates))
82
+ artifacts.push(...inv.step.updates);
83
+ return {
84
+ status: 'completed',
85
+ artifacts,
86
+ result: JSON.stringify({
87
+ simulated: true,
88
+ stepId: inv.step.id,
89
+ agent: inv.step.agent,
90
+ squad: inv.step.squad,
91
+ action: inv.step.action,
92
+ }),
93
+ };
94
+ }
95
+ }
96
+ exports.SimulatedStepExecutor = SimulatedStepExecutor;
97
+ class WorkflowEngine {
98
+ stateDir;
99
+ executor;
100
+ checkpointStore;
101
+ constructor(opts = {}) {
102
+ this.stateDir = opts.stateDir
103
+ || process.env.OPENLIFE_STATE_DIR
104
+ || path.join(process.cwd(), '.openlife');
105
+ this.executor = opts.executor || new SimulatedStepExecutor();
106
+ this.checkpointStore = opts.checkpointStore || new MissionState_1.MissionCheckpointStore();
107
+ }
108
+ /**
109
+ * Execute a workflow from scratch. Returns the final WorkflowRunState
110
+ * (the caller is responsible for inspecting `status` — terminal states
111
+ * are `completed`, `failed`, `aborted`, or `awaiting_input`).
112
+ */
113
+ async run(workflow, context = {}, opts = {}) {
114
+ (0, ToolsetGuard_1.assertToolsetAllowed)('workflows', 'WorkflowEngine.run');
115
+ // v1.3 — service mode requires explicit opt-in (Story 2.3).
116
+ // If the workflow declares mode: 'service', the caller MUST pass
117
+ // { allowServiceMode: true }. Silent task → service promotion refused.
118
+ const declaredMode = workflow.mode || 'task';
119
+ if (declaredMode === 'service' && !opts.allowServiceMode) {
120
+ const err = new Error(`workflow '${workflow.id}' declares mode='service' but caller did not pass allowServiceMode=true; service mode is explicit-only`);
121
+ err.code = 'service_mode_requires_explicit_opt_in';
122
+ throw err;
123
+ }
124
+ const runId = this.newRunId(workflow.id);
125
+ const state = {
126
+ runId,
127
+ workflowId: workflow.id,
128
+ status: 'pending',
129
+ startedAt: new Date().toISOString(),
130
+ completedSteps: [],
131
+ steps: {},
132
+ artifacts: [],
133
+ context: { ...context, __mode: declaredMode },
134
+ };
135
+ this.persistState(state);
136
+ this.emitEvent({
137
+ ts: new Date().toISOString(),
138
+ runId,
139
+ type: 'run.started',
140
+ detail: { workflowId: workflow.id, mode: declaredMode },
141
+ });
142
+ state.status = 'running';
143
+ this.persistState(state);
144
+ return await this.executeFrom(workflow, state, 0);
145
+ }
146
+ /**
147
+ * Read the persisted state for a run without modifying it.
148
+ */
149
+ status(runId) {
150
+ const filePath = this.stateFilePath(runId);
151
+ if (!fs.existsSync(filePath))
152
+ return null;
153
+ try {
154
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
155
+ }
156
+ catch {
157
+ return null;
158
+ }
159
+ }
160
+ /**
161
+ * Resume a previously-paused or crashed run. Requires the original
162
+ * Workflow (the engine does not persist workflow definitions — only
163
+ * runs of them, identified by `workflowId` in state).
164
+ */
165
+ async resume(workflow, runId) {
166
+ const state = this.status(runId);
167
+ if (!state) {
168
+ throw new Error(`workflow run not found: ${runId}`);
169
+ }
170
+ if (state.status === 'completed' || state.status === 'failed' || state.status === 'aborted') {
171
+ return state; // terminal — no-op
172
+ }
173
+ if (state.workflowId !== workflow.id) {
174
+ throw new Error(`workflowId mismatch: state has '${state.workflowId}', supplied '${workflow.id}'`);
175
+ }
176
+ this.emitEvent({ ts: new Date().toISOString(), runId, type: 'run.resumed', detail: { fromStatus: state.status } });
177
+ // Find the index to resume from: first non-completed executable step
178
+ const resumeIdx = this.findResumeIndex(workflow.sequence, state);
179
+ state.status = 'running';
180
+ this.persistState(state);
181
+ return await this.executeFrom(workflow, state, resumeIdx);
182
+ }
183
+ /**
184
+ * Mark a run as aborted. Idempotent.
185
+ */
186
+ abort(runId, reason = 'manual') {
187
+ const state = this.status(runId);
188
+ if (!state)
189
+ return null;
190
+ if (state.status === 'completed' || state.status === 'failed' || state.status === 'aborted') {
191
+ return state;
192
+ }
193
+ state.status = 'aborted';
194
+ state.failureReason = reason;
195
+ state.completedAt = new Date().toISOString();
196
+ this.persistState(state);
197
+ this.emitEvent({ ts: new Date().toISOString(), runId, type: 'run.aborted', detail: { reason } });
198
+ this.checkpointStore.clear(runId);
199
+ return state;
200
+ }
201
+ /**
202
+ * Provide user input for a step that paused with elicit. Re-runs that
203
+ * step with the input merged into context.
204
+ */
205
+ async provideInput(workflow, runId, stepId, payload) {
206
+ const state = this.status(runId);
207
+ if (!state)
208
+ throw new Error(`workflow run not found: ${runId}`);
209
+ if (state.status !== 'awaiting_input' || state.currentStep !== stepId) {
210
+ throw new Error(`run ${runId} is not awaiting input on step ${stepId} (status=${state.status}, currentStep=${state.currentStep ?? 'none'})`);
211
+ }
212
+ state.context = { ...state.context, [`elicit:${stepId}`]: payload };
213
+ state.status = 'running';
214
+ this.persistState(state);
215
+ // Mark this step's elicit gate as satisfied so the executor can proceed.
216
+ // The simplest approach: re-run from this step's index, but clear its
217
+ // elicit flag in-memory for this run only.
218
+ const idx = workflow.sequence.findIndex((e) => (0, WorkflowSchema_1.isExecutableStep)(e) && e.id === stepId);
219
+ if (idx < 0)
220
+ throw new Error(`step ${stepId} not in workflow ${workflow.id}`);
221
+ // Clone the workflow with elicit=false on this specific step so the
222
+ // resumed run advances past it.
223
+ const patched = {
224
+ ...workflow,
225
+ sequence: workflow.sequence.map((e) => {
226
+ if ((0, WorkflowSchema_1.isExecutableStep)(e) && e.id === stepId)
227
+ return { ...e, elicit: false };
228
+ return e;
229
+ }),
230
+ };
231
+ return await this.executeFrom(patched, state, idx);
232
+ }
233
+ // ─────────────────────────────────────────────────────────
234
+ // Internals
235
+ // ─────────────────────────────────────────────────────────
236
+ async executeFrom(workflow, state, startIdx) {
237
+ for (let i = startIdx; i < workflow.sequence.length; i++) {
238
+ const entry = workflow.sequence[i];
239
+ if (!(0, WorkflowSchema_1.isExecutableStep)(entry)) {
240
+ // Phase marker — narrative only, no execution
241
+ continue;
242
+ }
243
+ const step = entry;
244
+ // Skip already-completed steps (resume path)
245
+ if (state.completedSteps.includes(step.id)) {
246
+ continue;
247
+ }
248
+ // Optional step + condition not met → skip cleanly
249
+ if (step.optional && !this.conditionMet(step, state)) {
250
+ state.steps[step.id] = {
251
+ stepId: step.id,
252
+ status: 'skipped',
253
+ completedAt: new Date().toISOString(),
254
+ };
255
+ state.completedSteps.push(step.id);
256
+ this.persistState(state);
257
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'step.skipped', stepId: step.id, detail: { reason: 'optional_condition_not_met' } });
258
+ continue;
259
+ }
260
+ // Begin step
261
+ const stepRec = {
262
+ stepId: step.id,
263
+ status: 'running',
264
+ startedAt: new Date().toISOString(),
265
+ };
266
+ state.steps[step.id] = stepRec;
267
+ state.currentStep = step.id;
268
+ this.persistState(state);
269
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'step.started', stepId: step.id });
270
+ let result;
271
+ try {
272
+ result = await this.executor.execute({ runId: state.runId, step, context: state.context || {} });
273
+ }
274
+ catch (err) {
275
+ stepRec.status = 'failed';
276
+ stepRec.error = err instanceof Error ? err.message : String(err);
277
+ stepRec.completedAt = new Date().toISOString();
278
+ state.status = 'failed';
279
+ state.failureReason = `step ${step.id} threw: ${stepRec.error}`;
280
+ state.completedAt = new Date().toISOString();
281
+ this.persistState(state);
282
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'step.failed', stepId: step.id, detail: { error: stepRec.error } });
283
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'run.failed', detail: { failedStep: step.id } });
284
+ return state;
285
+ }
286
+ if (result.status === 'awaiting_input') {
287
+ state.status = 'awaiting_input';
288
+ stepRec.status = 'running'; // stays running until input arrives
289
+ this.persistState(state);
290
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'run.awaiting_input', stepId: step.id });
291
+ return state;
292
+ }
293
+ if (result.status === 'failed') {
294
+ stepRec.status = 'failed';
295
+ stepRec.error = result.error || 'unknown failure';
296
+ stepRec.completedAt = new Date().toISOString();
297
+ state.status = 'failed';
298
+ state.failureReason = `step ${step.id} failed: ${stepRec.error}`;
299
+ state.completedAt = new Date().toISOString();
300
+ this.persistState(state);
301
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'step.failed', stepId: step.id, detail: { error: stepRec.error } });
302
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'run.failed', detail: { failedStep: step.id } });
303
+ return state;
304
+ }
305
+ // completed or skipped — both advance the run
306
+ stepRec.status = result.status;
307
+ stepRec.completedAt = new Date().toISOString();
308
+ stepRec.artifacts = result.artifacts;
309
+ stepRec.result = result.result;
310
+ state.completedSteps.push(step.id);
311
+ if (result.artifacts)
312
+ state.artifacts.push(...result.artifacts);
313
+ state.currentStep = undefined;
314
+ state.lastCheckpointAt = new Date().toISOString();
315
+ this.persistState(state);
316
+ this.checkpointStore.saveCheckpoint(state.runId, step.id, {
317
+ workflowId: workflow.id,
318
+ completedSteps: state.completedSteps,
319
+ artifacts: state.artifacts,
320
+ });
321
+ this.emitEvent({
322
+ ts: new Date().toISOString(),
323
+ runId: state.runId,
324
+ type: result.status === 'completed' ? 'step.completed' : 'step.skipped',
325
+ stepId: step.id,
326
+ detail: { artifacts: result.artifacts || [] },
327
+ });
328
+ }
329
+ // All steps processed → mark run completed
330
+ state.status = 'completed';
331
+ state.completedAt = new Date().toISOString();
332
+ this.persistState(state);
333
+ this.emitEvent({ ts: new Date().toISOString(), runId: state.runId, type: 'run.completed', detail: { totalSteps: state.completedSteps.length } });
334
+ this.checkpointStore.clear(state.runId);
335
+ return state;
336
+ }
337
+ conditionMet(step, state) {
338
+ if (!step.condition)
339
+ return true;
340
+ // v1.4 (Story 10.3) — full expression engine: AND / OR / NOT / == / !=
341
+ // plus parentheses. Backward-compat: a bare identifier `foo` still
342
+ // evaluates to `ctx.foo === true`.
343
+ const { evaluateCondition } = require('./ConditionParser');
344
+ const ctx = (state.context || {});
345
+ return evaluateCondition(step.condition, ctx);
346
+ }
347
+ findResumeIndex(sequence, state) {
348
+ for (let i = 0; i < sequence.length; i++) {
349
+ const e = sequence[i];
350
+ if (!(0, WorkflowSchema_1.isExecutableStep)(e))
351
+ continue;
352
+ if (!state.completedSteps.includes(e.id))
353
+ return i;
354
+ }
355
+ return sequence.length;
356
+ }
357
+ persistState(state) {
358
+ (0, AtomicWriter_1.writeJsonAtomic)(this.stateFilePath(state.runId), state);
359
+ }
360
+ emitEvent(event) {
361
+ (0, AtomicWriter_1.appendJsonlAtomic)(this.eventLogPath(event.runId), event);
362
+ }
363
+ stateFilePath(runId) {
364
+ return path.join(this.stateDir, 'workflows', `${runId}.json`);
365
+ }
366
+ eventLogPath(runId) {
367
+ return path.join(this.stateDir, 'workflows', 'events', `${runId}.jsonl`);
368
+ }
369
+ newRunId(workflowId) {
370
+ const ts = Date.now().toString(36);
371
+ const rnd = crypto.randomBytes(4).toString('hex');
372
+ return `${workflowId}-${ts}-${rnd}`;
373
+ }
374
+ /** Exposed for tests so they can assert resolved storage location. */
375
+ _stateDir() {
376
+ return this.stateDir;
377
+ }
378
+ }
379
+ exports.WorkflowEngine = WorkflowEngine;