@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,88 @@
1
+ "use strict";
2
+ /**
3
+ * test_process_sandbox.ts — Story 15.1 (v1.5, research-track)
4
+ *
5
+ * Unit-tests the ProcessSandbox flag construction and Node-version
6
+ * downgrade behaviour without actually spawning anything. The wrapper's
7
+ * value is in the argv it builds; running real Node sub-processes is
8
+ * left to v1.6 integration tests once the wrapper is wired into a
9
+ * production site.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const ProcessSandbox_1 = require("./orchestrator/ProcessSandbox");
13
+ function assertTrue(cond, label) {
14
+ if (!cond)
15
+ throw new Error(`ASSERT_FAILED[${label}]`);
16
+ }
17
+ function arrEq(a, b) {
18
+ if (a.length !== b.length)
19
+ return false;
20
+ for (let i = 0; i < a.length; i++)
21
+ if (a[i] !== b[i])
22
+ return false;
23
+ return true;
24
+ }
25
+ // ── Scenario 1: Node 20 → permission flags injected ────────────────────
26
+ {
27
+ const sb = new ProcessSandbox_1.ProcessSandbox({
28
+ nodeMajor: 20,
29
+ allowFsRead: ['/tmp', '/repo'],
30
+ allowFsWrite: ['/repo/.artifacts'],
31
+ });
32
+ assertTrue(sb.supportsEnforcement(), '[15.1] Node 20 supports enforcement');
33
+ const flags = sb.buildPermissionFlags();
34
+ assertTrue(arrEq(flags, ['--permission', '--allow-fs-read=/tmp', '--allow-fs-read=/repo', '--allow-fs-write=/repo/.artifacts']), `[15.1] flags ordered correctly (got ${JSON.stringify(flags)})`);
35
+ console.log('[15.1] Node 20 enforcement flags ✓');
36
+ }
37
+ // ── Scenario 2: Node 18 → no enforcement, empty flag list ─────────────
38
+ {
39
+ const sb = new ProcessSandbox_1.ProcessSandbox({ nodeMajor: 18, allowFsRead: ['/tmp'] });
40
+ assertTrue(!sb.supportsEnforcement(), '[15.1] Node 18 does not support enforcement');
41
+ assertTrue(arrEq(sb.buildPermissionFlags(), []), '[15.1] Node 18 → empty flags');
42
+ console.log('[15.1] Node 18 downgrades gracefully ✓');
43
+ }
44
+ // ── Scenario 3: capability toggles add their flags ─────────────────────
45
+ {
46
+ const sb = new ProcessSandbox_1.ProcessSandbox({ nodeMajor: 22, allowChildProcess: true, allowWorker: true });
47
+ const flags = sb.buildPermissionFlags();
48
+ assertTrue(flags.includes('--allow-child-process'), '[15.1] allowChildProcess adds flag');
49
+ assertTrue(flags.includes('--allow-worker'), '[15.1] allowWorker adds flag');
50
+ assertTrue(!flags.includes('--allow-wasi'), '[15.1] absent options stay absent');
51
+ console.log('[15.1] capability toggles correct ✓');
52
+ }
53
+ // ── Scenario 4: spawn injects flags only for node binaries ────────────
54
+ async function scenarioSpawn() {
55
+ let lastCommand = '';
56
+ let lastArgs = [];
57
+ const fakeSpawn = ((command, args) => {
58
+ lastCommand = command;
59
+ lastArgs = args;
60
+ const stub = {
61
+ stdout: { on: (_, _cb) => { } },
62
+ stderr: { on: (_, _cb) => { } },
63
+ on: (event, cb) => {
64
+ if (event === 'close')
65
+ setTimeout(() => cb(0, null), 0);
66
+ },
67
+ };
68
+ return stub;
69
+ });
70
+ const sb = new ProcessSandbox_1.ProcessSandbox({ nodeMajor: 20, allowFsRead: ['/repo'], spawnImpl: fakeSpawn });
71
+ const r1 = await sb.spawn('node', ['build.js']);
72
+ assertTrue(r1.enforced, '[15.1] node command is enforced');
73
+ assertTrue(lastCommand === 'node', '[15.1] node command preserved');
74
+ assertTrue(arrEq(lastArgs, ['--permission', '--allow-fs-read=/repo', 'build.js']), `[15.1] permission flags inserted before user argv (got ${JSON.stringify(lastArgs)})`);
75
+ assertTrue(r1.code === 0 && r1.signal === null, '[15.1] result envelope normal');
76
+ console.log('[15.1] spawn(node) injects permission flags ✓');
77
+ const r2 = await sb.spawn('git', ['status']);
78
+ assertTrue(!r2.enforced, '[15.1] non-node command not enforced');
79
+ assertTrue(lastCommand === 'git', '[15.1] git command preserved');
80
+ assertTrue(arrEq(lastArgs, ['status']), '[15.1] git argv unchanged');
81
+ console.log('[15.1] spawn(git) is plain pass-through ✓');
82
+ }
83
+ scenarioSpawn()
84
+ .then(() => { console.log('TEST_PROCESS_SANDBOX_OK'); })
85
+ .catch((err) => {
86
+ console.error('[process-sandbox] FAILED:', err instanceof Error ? err.message : err);
87
+ process.exit(1);
88
+ });
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * test_profile_toolset_mcp.ts — Stories 5.2 + 5.3 + 5.4
4
+ *
5
+ * Combined regression for ProfileManager + ToolsetRegistry +
6
+ * ExternalCatalogRegistry.import.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const os = __importStar(require("os"));
45
+ const ProfileManager_1 = require("./cli/ProfileManager");
46
+ const ToolsetRegistry_1 = require("./orchestrator/toolset/ToolsetRegistry");
47
+ const ToolsetSchema_1 = require("./orchestrator/toolset/ToolsetSchema");
48
+ const ExternalCatalogRegistry_1 = require("./orchestrator/ExternalCatalogRegistry");
49
+ function assertTrue(cond, label) {
50
+ if (!cond)
51
+ throw new Error(`ASSERT_FAILED[${label}]`);
52
+ }
53
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'profile-toolset-mcp-'));
54
+ try {
55
+ // ── ProfileManager ─────────────────────────────────────────────
56
+ const pm = new ProfileManager_1.ProfileManager({ stateDir: tmp });
57
+ assertTrue(pm.list().length === 0, 'profiles start empty');
58
+ const safe = pm.create({
59
+ id: 'sandboxed',
60
+ name: 'Sandboxed',
61
+ description: 'Locked-down profile',
62
+ toolsetAllowed: ['file', 'memory'],
63
+ });
64
+ assertTrue(safe.id === 'sandboxed', '[5.2] create returns profile');
65
+ assertTrue(safe.memoryNamespace === 'profile-sandboxed', '[5.2] auto-namespace');
66
+ assertTrue(pm.list().length === 1, '[5.2] list includes new profile');
67
+ console.log('[5.2] ProfileManager.create + list ✓');
68
+ // use + active
69
+ const useRes = pm.use('sandboxed');
70
+ assertTrue(useRes.ok, '[5.2] use ok');
71
+ const { profileId, profile } = pm.active();
72
+ assertTrue(profileId === 'sandboxed' && profile?.toolsetAllowed.length === 2, '[5.2] active profile resolved');
73
+ console.log('[5.2] ProfileManager.use + active ✓');
74
+ // invalid id rejected
75
+ let invalidIdRejected = false;
76
+ try {
77
+ pm.create({ id: 'BAD ID', name: 'x' });
78
+ }
79
+ catch (e) {
80
+ invalidIdRejected = e.code === 'invalid_profile_id';
81
+ }
82
+ assertTrue(invalidIdRejected, '[5.2] invalid_profile_id surfaced');
83
+ console.log('[5.2] invalid id rejected ✓');
84
+ // import/export
85
+ const exported = pm.export('sandboxed');
86
+ assertTrue(exported !== null && exported.id === 'sandboxed', '[5.2] export round-trip');
87
+ const importRes = pm.import({ ...exported, id: 'imported-from-export' });
88
+ assertTrue(importRes.ok, '[5.2] import ok');
89
+ assertTrue(pm.list().length === 2, '[5.2] imported visible in list');
90
+ console.log('[5.2] ProfileManager.export + import ✓');
91
+ // ── ToolsetRegistry ─────────────────────────────────────────────
92
+ const ts = new ToolsetRegistry_1.ToolsetRegistry({ profileManager: pm });
93
+ assertTrue(ts.list().length === ToolsetSchema_1.ALL_TOOLSETS.length, '[5.3] list returns all categories');
94
+ const fileDecision = ts.isAllowed('file');
95
+ assertTrue(fileDecision.allowed, '[5.3] file allowed on sandboxed profile');
96
+ const browserDecision = ts.isAllowed('browser');
97
+ assertTrue(!browserDecision.allowed, '[5.3] browser denied on sandboxed profile');
98
+ console.log('[5.3] ToolsetRegistry decisions ✓');
99
+ // Wildcard profile allows all
100
+ pm.create({ id: 'powerful', name: 'Powerful', toolsetAllowed: ['*'] });
101
+ pm.use('powerful');
102
+ const ts2 = new ToolsetRegistry_1.ToolsetRegistry({ profileManager: pm });
103
+ for (const c of ToolsetSchema_1.ALL_TOOLSETS) {
104
+ assertTrue(ts2.isAllowed(c).allowed, `[5.3] wildcard allows ${c}`);
105
+ }
106
+ console.log('[5.3] wildcard profile allows all ✓');
107
+ // Empty allowlist denies everything
108
+ pm.create({ id: 'no-tools', name: 'No tools', toolsetAllowed: [] });
109
+ const ts3 = new ToolsetRegistry_1.ToolsetRegistry({ profileManager: pm });
110
+ assertTrue(!ts3.isAllowed('file', 'no-tools').allowed, '[5.3] empty allowlist denies file');
111
+ console.log('[5.3] empty allowlist denies all ✓');
112
+ // ── ExternalCatalogRegistry.import ──────────────────────────────
113
+ const reg = new ExternalCatalogRegistry_1.ExternalCatalogRegistry();
114
+ const ok = reg.import('github', 'some-pack');
115
+ assertTrue(ok.ok, '[5.4] import-allowed source returns ok');
116
+ const refOnly = reg.import('skills-sh', 'some-pack');
117
+ assertTrue(!refOnly.ok && refOnly.error === 'source_is_reference_only', '[5.4] reference-only refused');
118
+ const missing = reg.import('nonexistent', 'some-pack');
119
+ assertTrue(!missing.ok && missing.error === 'source_not_found', '[5.4] missing source returns source_not_found');
120
+ console.log('[5.4] ExternalCatalogRegistry.import ✓');
121
+ }
122
+ finally {
123
+ fs.rmSync(tmp, { recursive: true, force: true });
124
+ }
125
+ console.log('TEST_PROFILE_TOOLSET_MCP_OK');
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ /**
3
+ * test_queue_scheduler — Story 6.3 regression suite.
4
+ *
5
+ * Four scenarios:
6
+ * 1. enqueue + tick + happy path: missions transition pending→running→
7
+ * completed; queue file persists each transition atomically.
8
+ * 2. Backpressure: maxConcurrent caps the in-flight set; extras wait.
9
+ * 3. Lock-respect: a mission whose lock is already held by another
10
+ * DistributedLock instance is NOT picked up.
11
+ * 4. reconcileOrphans: a queue with stale `running` items (no holder)
12
+ * resets them to `pending` on the next start.
13
+ *
14
+ * Prints TEST_QUEUE_SCHEDULER_OK on full pass.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ const fs = __importStar(require("fs"));
51
+ const os = __importStar(require("os"));
52
+ const path = __importStar(require("path"));
53
+ const QueueScheduler_1 = require("./orchestrator/QueueScheduler");
54
+ const DistributedLock_1 = require("./orchestrator/util/DistributedLock");
55
+ const AtomicWriter_1 = require("./orchestrator/util/AtomicWriter");
56
+ function assert(cond, msg) {
57
+ if (!cond)
58
+ throw new Error(`assertion failed: ${msg}`);
59
+ }
60
+ function mkTmp() {
61
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'qs-test-'));
62
+ }
63
+ function rmTmp(dir) {
64
+ try {
65
+ fs.rmSync(dir, { recursive: true, force: true });
66
+ }
67
+ catch { /* ignore */ }
68
+ }
69
+ class CountingExecutor {
70
+ delayMs;
71
+ failFor;
72
+ seen = [];
73
+ concurrentPeak = 0;
74
+ inFlight = 0;
75
+ constructor(delayMs = 20, failFor = new Set()) {
76
+ this.delayMs = delayMs;
77
+ this.failFor = failFor;
78
+ }
79
+ async execute(m) {
80
+ this.inFlight += 1;
81
+ this.concurrentPeak = Math.max(this.concurrentPeak, this.inFlight);
82
+ this.seen.push(m.id);
83
+ await new Promise((r) => setTimeout(r, this.delayMs));
84
+ this.inFlight -= 1;
85
+ if (this.failFor.has(m.id))
86
+ return { status: 'failed', error: 'scripted failure' };
87
+ return { status: 'completed' };
88
+ }
89
+ }
90
+ function makeScheduler(tmp, opts = {}) {
91
+ const queueFile = path.join(tmp, '.openlife', 'agent-queue.json');
92
+ return new QueueScheduler_1.QueueScheduler({
93
+ queueFile,
94
+ pollIntervalMs: 100_000, // we'll call tick() manually
95
+ maxConcurrent: opts.maxConcurrent ?? 3,
96
+ executor: opts.executor,
97
+ lock: opts.lock,
98
+ maxAttempts: opts.maxAttempts,
99
+ });
100
+ }
101
+ async function waitFor(predicate, timeoutMs = 2_000) {
102
+ const deadline = Date.now() + timeoutMs;
103
+ while (Date.now() < deadline) {
104
+ if (predicate())
105
+ return;
106
+ await new Promise((r) => setTimeout(r, 20));
107
+ }
108
+ throw new Error('waitFor timed out');
109
+ }
110
+ // ─────────────────────────────────────────────────────────────
111
+ // Scenario 1 — happy path
112
+ // ─────────────────────────────────────────────────────────────
113
+ async function scenarioHappyPath() {
114
+ const tmp = mkTmp();
115
+ try {
116
+ const exec = new CountingExecutor(10);
117
+ const sched = makeScheduler(tmp, { executor: exec, maxConcurrent: 3 });
118
+ sched.enqueue({ id: 'm-1', goal: 'do thing 1' });
119
+ sched.enqueue({ id: 'm-2', goal: 'do thing 2' });
120
+ sched.enqueue({ id: 'm-3', goal: 'do thing 3' });
121
+ await sched.tick();
122
+ // Wait for all to complete
123
+ await waitFor(() => sched.list().every((m) => m.status === 'completed'));
124
+ const items = sched.list();
125
+ assert(items.length === 3, `expected 3 items, got ${items.length}`);
126
+ assert(items.every((m) => m.status === 'completed'), 'all must be completed');
127
+ assert(exec.seen.length === 3, `executor must have seen 3, got ${exec.seen.length}`);
128
+ console.log('✅ scenario 1: enqueue + happy path (3 missions completed)');
129
+ }
130
+ finally {
131
+ rmTmp(tmp);
132
+ }
133
+ }
134
+ // ─────────────────────────────────────────────────────────────
135
+ // Scenario 2 — backpressure
136
+ // ─────────────────────────────────────────────────────────────
137
+ async function scenarioBackpressure() {
138
+ const tmp = mkTmp();
139
+ try {
140
+ const exec = new CountingExecutor(80); // each takes ~80ms
141
+ const sched = makeScheduler(tmp, { executor: exec, maxConcurrent: 2 });
142
+ for (let i = 0; i < 5; i++)
143
+ sched.enqueue({ id: `m-${i}`, goal: `goal ${i}` });
144
+ // First tick: picks 2; others stay pending
145
+ await sched.tick();
146
+ // While the first 2 are still in flight, peak should be 2
147
+ await new Promise((r) => setTimeout(r, 40));
148
+ assert(exec.concurrentPeak <= 2, `concurrent peak must respect maxConcurrent, got ${exec.concurrentPeak}`);
149
+ // Wait for first 2 to complete, then tick again
150
+ await waitFor(() => sched.list().filter((m) => m.status === 'completed').length >= 2);
151
+ await sched.tick();
152
+ await waitFor(() => sched.list().filter((m) => m.status === 'completed').length >= 4);
153
+ await sched.tick();
154
+ await waitFor(() => sched.list().every((m) => m.status === 'completed'));
155
+ assert(exec.concurrentPeak <= 2, `final peak must not exceed maxConcurrent, got ${exec.concurrentPeak}`);
156
+ console.log(`✅ scenario 2: backpressure (peak ${exec.concurrentPeak} ≤ maxConcurrent=2)`);
157
+ }
158
+ finally {
159
+ rmTmp(tmp);
160
+ }
161
+ }
162
+ // ─────────────────────────────────────────────────────────────
163
+ // Scenario 3 — lock-respect (mission lock pre-held)
164
+ // ─────────────────────────────────────────────────────────────
165
+ async function scenarioLockRespect() {
166
+ const tmp = mkTmp();
167
+ try {
168
+ const baseDir = path.join(tmp, '.openlife', 'locks');
169
+ const externalLock = new DistributedLock_1.DistributedLock({ baseDir });
170
+ const sharedLock = new DistributedLock_1.DistributedLock({ baseDir });
171
+ // Pre-hold the lock for mission m-locked
172
+ const acq = externalLock.acquire('mission:m-locked', 60_000, { startHeartbeat: false });
173
+ assert(acq.ok, 'external acquire must succeed');
174
+ const exec = new CountingExecutor(10);
175
+ const sched = makeScheduler(tmp, { executor: exec, maxConcurrent: 5, lock: sharedLock });
176
+ sched.enqueue({ id: 'm-locked', goal: 'should be skipped' });
177
+ sched.enqueue({ id: 'm-free', goal: 'should run' });
178
+ await sched.tick();
179
+ await waitFor(() => sched.list().find((m) => m.id === 'm-free')?.status === 'completed');
180
+ const locked = sched.list().find((m) => m.id === 'm-locked');
181
+ assert(locked?.status === 'pending', `locked mission must stay pending, got ${locked?.status}`);
182
+ assert(exec.seen.includes('m-free'), 'free mission must have executed');
183
+ assert(!exec.seen.includes('m-locked'), 'locked mission must NOT have executed');
184
+ // Release external lock — next tick should now pick it up
185
+ externalLock.release(acq.lockId);
186
+ await sched.tick();
187
+ await waitFor(() => sched.list().find((m) => m.id === 'm-locked')?.status === 'completed');
188
+ console.log('✅ scenario 3: lock-respect (locked mission skipped, picked up after release)');
189
+ }
190
+ finally {
191
+ rmTmp(tmp);
192
+ }
193
+ }
194
+ // ─────────────────────────────────────────────────────────────
195
+ // Scenario 4 — reconcile orphans
196
+ // ─────────────────────────────────────────────────────────────
197
+ async function scenarioReconcileOrphans() {
198
+ const tmp = mkTmp();
199
+ try {
200
+ const queueFile = path.join(tmp, '.openlife', 'agent-queue.json');
201
+ // Seed queue with a "running" orphan (simulates a crash mid-flight)
202
+ (0, AtomicWriter_1.writeJsonAtomic)(queueFile, {
203
+ items: [
204
+ { id: 'm-orphan', goal: 'crashed last run', status: 'running', enqueuedAt: new Date().toISOString(), attempts: 1, startedAt: new Date(Date.now() - 60_000).toISOString() },
205
+ { id: 'm-fresh', goal: 'never started', status: 'pending', enqueuedAt: new Date().toISOString(), attempts: 0 },
206
+ ],
207
+ lastFlushedAt: new Date().toISOString(),
208
+ });
209
+ const exec = new CountingExecutor(10);
210
+ const sched = makeScheduler(tmp, { executor: exec });
211
+ const resetCount = sched.reconcileOrphans();
212
+ assert(resetCount === 1, `expected 1 orphan reset, got ${resetCount}`);
213
+ assert(sched.list().find((m) => m.id === 'm-orphan')?.status === 'pending', 'orphan must be reset to pending');
214
+ // Now tick — both should complete
215
+ await sched.tick();
216
+ await waitFor(() => sched.list().every((m) => m.status === 'completed'));
217
+ assert(exec.seen.includes('m-orphan') && exec.seen.includes('m-fresh'), 'both must execute after reconcile');
218
+ console.log('✅ scenario 4: reconcileOrphans resets stale running missions');
219
+ }
220
+ finally {
221
+ rmTmp(tmp);
222
+ }
223
+ }
224
+ // ─────────────────────────────────────────────────────────────
225
+ // Driver
226
+ // ─────────────────────────────────────────────────────────────
227
+ async function main() {
228
+ console.log('🧪 test_queue_scheduler — Story 6.3 regression suite');
229
+ await scenarioHappyPath();
230
+ await scenarioBackpressure();
231
+ await scenarioLockRespect();
232
+ await scenarioReconcileOrphans();
233
+ console.log('');
234
+ console.log('TEST_QUEUE_SCHEDULER_OK');
235
+ }
236
+ main().catch((err) => {
237
+ console.error('❌ test_queue_scheduler FAILED:', err instanceof Error ? err.message : err);
238
+ process.exit(1);
239
+ });
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ReleaseWorkflow_1 = require("./orchestrator/ReleaseWorkflow");
4
+ function assert(condition, message) {
5
+ if (!condition)
6
+ throw new Error(message);
7
+ }
8
+ async function main() {
9
+ const workflow = new ReleaseWorkflow_1.ReleaseWorkflow();
10
+ const checklist = workflow.create('release-gate-test', [
11
+ { name: 'doctor:models.json', ok: true },
12
+ { name: 'runtime:codex', ok: true },
13
+ { name: 'harness:runtime-policy-chain', ok: true }
14
+ ]);
15
+ assert(Array.isArray(checklist.checks), 'release gate workflow should return checks');
16
+ assert(checklist.checks.length === 3, 'release gate workflow should persist provided checks');
17
+ assert(checklist.approved === true, 'release gate workflow should approve when all checks pass');
18
+ console.log('TEST_RELEASE_GATE_OK');
19
+ }
20
+ main().catch((error) => {
21
+ console.error(error.message || error);
22
+ process.exit(1);
23
+ });
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ /**
3
+ * test_remote_publish.ts — Story 14.1 (v1.5)
4
+ *
5
+ * Asserts:
6
+ * 1. RemotePublisher.isConfigured() reflects the env flag.
7
+ * 2. Without OPENLIFE_REMOTE_PUBLISH_URL, publishAsset returns
8
+ * `remote_publish_not_configured` without making a network call.
9
+ * 3. With a stubbed fetch and a valid PUT URL, publishAsset issues
10
+ * a single PUT carrying:
11
+ * - Content-Type: text/markdown
12
+ * - X-Asset-Sha256 / X-Asset-Kind / X-Asset-Id headers
13
+ * - Authorization: Bearer <token> when token env is set
14
+ * - The asset body
15
+ * 4. Non-2xx response surfaces as `http_<status>`; never throws.
16
+ * 5. fetch throwing surfaces as `fetch_error`.
17
+ * 6. SquadCreator.publishWithRemote composes local publish + remote PUT
18
+ * and carries both results on the envelope.
19
+ * 7. SHA mismatch (caller-provided != content-hash) is caught locally
20
+ * and returns `sha_mismatch_local` without fetch ever being called.
21
+ */
22
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
27
+ }
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
55
+ Object.defineProperty(exports, "__esModule", { value: true });
56
+ const fs = __importStar(require("fs"));
57
+ const os = __importStar(require("os"));
58
+ const path = __importStar(require("path"));
59
+ const crypto = __importStar(require("crypto"));
60
+ function assertTrue(cond, label) {
61
+ if (!cond)
62
+ throw new Error(`ASSERT_FAILED[${label}]`);
63
+ }
64
+ function mockFetch(captured, response) {
65
+ return (async (input, init) => {
66
+ const initObj = (init || {});
67
+ const headers = {};
68
+ if (initObj.headers && typeof initObj.headers === 'object') {
69
+ for (const [k, v] of Object.entries(initObj.headers))
70
+ headers[k] = v;
71
+ }
72
+ captured.calls += 1;
73
+ captured.lastUrl = String(input);
74
+ captured.lastInit = { method: initObj.method, headers, body: typeof initObj.body === 'string' ? initObj.body : undefined };
75
+ const respHeaders = new Map();
76
+ if (response.etag)
77
+ respHeaders.set('etag', response.etag);
78
+ return {
79
+ status: response.status,
80
+ headers: { get: (k) => respHeaders.get(k.toLowerCase()) ?? null },
81
+ text: async () => response.body || '',
82
+ };
83
+ });
84
+ }
85
+ async function main() {
86
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'remote-pub-'));
87
+ process.env.OPENLIFE_STATE_DIR = tmp;
88
+ try {
89
+ const { RemotePublisher } = require('./orchestrator/RemotePublisher');
90
+ // ── Scenario 1 + 2: unconfigured returns stable code, no fetch ─────
91
+ delete process.env.OPENLIFE_REMOTE_PUBLISH_URL;
92
+ delete process.env.OPENLIFE_REMOTE_PUBLISH_TOKEN;
93
+ const captured0 = { calls: 0 };
94
+ const pub0 = new RemotePublisher({ fetchImpl: mockFetch(captured0, { status: 200 }) });
95
+ assertTrue(!pub0.isConfigured(), '[14.1] unconfigured isConfigured=false');
96
+ const assetFile = path.join(tmp, 'asset.md');
97
+ fs.writeFileSync(assetFile, '# hi\n', 'utf-8');
98
+ const sha = crypto.createHash('sha256').update('# hi\n').digest('hex');
99
+ const r0 = await pub0.publishAsset('squad', 'demo', sha, assetFile);
100
+ assertTrue(!r0.ok && r0.error === 'remote_publish_not_configured', `[14.1] unconfigured error code (got ${r0.error})`);
101
+ assertTrue(captured0.calls === 0, '[14.1] unconfigured does not fetch');
102
+ console.log('[14.1] unconfigured → stable error code, no fetch ✓');
103
+ // ── Scenario 3: happy path with token ──────────────────────────────
104
+ const captured1 = { calls: 0 };
105
+ const pub1 = new RemotePublisher({
106
+ baseUrl: 'https://registry.example/openlife',
107
+ token: 'tk-test',
108
+ fetchImpl: mockFetch(captured1, { status: 201, etag: 'W/"deadbeef"' }),
109
+ });
110
+ const r1 = await pub1.publishAsset('squad', 'demo', sha, assetFile);
111
+ assertTrue(r1.ok && r1.status === 201, `[14.1] happy path status=201 (got ${r1.status})`);
112
+ assertTrue(r1.etag === 'W/"deadbeef"', '[14.1] etag passthrough');
113
+ assertTrue(captured1.calls === 1, '[14.1] exactly one PUT');
114
+ assertTrue(captured1.lastInit?.method === 'PUT', `[14.1] verb is PUT (got ${captured1.lastInit?.method})`);
115
+ assertTrue(captured1.lastUrl === `https://registry.example/openlife/squad/demo/${encodeURIComponent(sha)}.md`, `[14.1] URL shape correct (got ${captured1.lastUrl})`);
116
+ assertTrue(captured1.lastInit?.headers?.['Content-Type'] === 'text/markdown', '[14.1] content-type set');
117
+ assertTrue(captured1.lastInit?.headers?.['X-Asset-Sha256'] === sha, '[14.1] sha header set');
118
+ assertTrue(captured1.lastInit?.headers?.['X-Asset-Kind'] === 'squad', '[14.1] kind header set');
119
+ assertTrue(captured1.lastInit?.headers?.['X-Asset-Id'] === 'demo', '[14.1] id header set');
120
+ assertTrue(captured1.lastInit?.headers?.['Authorization'] === 'Bearer tk-test', '[14.1] bearer auth set');
121
+ assertTrue(captured1.lastInit?.body === '# hi\n', '[14.1] body is the asset contents');
122
+ console.log('[14.1] happy path PUT request shape ✓');
123
+ // ── Scenario 4: non-2xx surfaces as http_<status> ──────────────────
124
+ const captured2 = { calls: 0 };
125
+ const pub2 = new RemotePublisher({ baseUrl: 'https://r.example', fetchImpl: mockFetch(captured2, { status: 403 }) });
126
+ const r2 = await pub2.publishAsset('skill', 'foo', sha, assetFile);
127
+ assertTrue(!r2.ok && r2.error === 'http_403', `[14.1] 403 → http_403 (got ${r2.error})`);
128
+ console.log('[14.1] non-2xx → http_<status> ✓');
129
+ // ── Scenario 5: fetch throws → fetch_error ────────────────────────
130
+ const throwingFetch = (async () => { throw new Error('network down'); });
131
+ const pub3 = new RemotePublisher({ baseUrl: 'https://r.example', fetchImpl: throwingFetch });
132
+ const r3 = await pub3.publishAsset('squad', 'foo', sha, assetFile);
133
+ assertTrue(!r3.ok && r3.error === 'fetch_error', `[14.1] thrown fetch → fetch_error (got ${r3.error})`);
134
+ console.log('[14.1] fetch throws → fetch_error, no crash ✓');
135
+ // ── Scenario 7: SHA mismatch caught locally ────────────────────────
136
+ const captured4 = { calls: 0 };
137
+ const pub4 = new RemotePublisher({ baseUrl: 'https://r.example', fetchImpl: mockFetch(captured4, { status: 200 }) });
138
+ const r4 = await pub4.publishAsset('squad', 'demo', '0'.repeat(64), assetFile);
139
+ assertTrue(!r4.ok && r4.error === 'sha_mismatch_local', `[14.1] sha mismatch caught (got ${r4.error})`);
140
+ assertTrue(captured4.calls === 0, '[14.1] sha mismatch → no fetch');
141
+ console.log('[14.1] sha mismatch detected locally, no fetch ✓');
142
+ // ── Scenario 6: SquadCreator.publishWithRemote composes both ───────
143
+ // We stub the RemotePublisher require to inject a mock fetch.
144
+ const pubPath = require.resolve('./orchestrator/RemotePublisher');
145
+ const origPub = require.cache[pubPath];
146
+ const captured5 = { calls: 0 };
147
+ require.cache[pubPath] = {
148
+ ...origPub,
149
+ exports: {
150
+ RemotePublisher: class {
151
+ async publishAsset(kind, id, sha256) {
152
+ captured5.calls += 1;
153
+ return { ok: true, url: `https://stub/${kind}/${id}/${sha256}.md`, status: 201 };
154
+ }
155
+ },
156
+ },
157
+ };
158
+ try {
159
+ const { SquadCreator } = require('./orchestrator/SquadCreator');
160
+ const sc = new SquadCreator({
161
+ catalogRoot: path.join(tmp, '.catalog', 'squads'),
162
+ templateRoot: path.resolve(__dirname, '..', 'dist-templates', 'squad-template'),
163
+ });
164
+ const seed = sc.create({
165
+ id: 'compose-squad', name: 'Compose', description: 'demo', version: '0.1.0', status: 'draft',
166
+ agents: [{ id: 'lead', name: 'Lead', role: 'lead' }],
167
+ });
168
+ assertTrue(seed.ok, '[14.1] seed squad created');
169
+ const composed = await sc.publishWithRemote('compose-squad');
170
+ assertTrue(composed.ok, '[14.1] local publish ok');
171
+ assertTrue(composed.remote && composed.remote.ok, '[14.1] remote publish ok');
172
+ assertTrue(captured5.calls === 1, '[14.1] composed call invokes RemotePublisher exactly once');
173
+ }
174
+ finally {
175
+ if (origPub)
176
+ require.cache[pubPath] = origPub;
177
+ else
178
+ delete require.cache[pubPath];
179
+ }
180
+ console.log('[14.1] SquadCreator.publishWithRemote composes local + remote ✓');
181
+ }
182
+ finally {
183
+ delete process.env.OPENLIFE_STATE_DIR;
184
+ delete process.env.OPENLIFE_REMOTE_PUBLISH_URL;
185
+ delete process.env.OPENLIFE_REMOTE_PUBLISH_TOKEN;
186
+ fs.rmSync(tmp, { recursive: true, force: true });
187
+ }
188
+ console.log('TEST_REMOTE_PUBLISH_OK');
189
+ }
190
+ main().catch((err) => {
191
+ console.error('[remote-publish] FAILED:', err instanceof Error ? err.message : err);
192
+ process.exit(1);
193
+ });