11import { input } from "@inquirer/prompts" ;
2+ import axios from "axios" ;
23import cac , { type CAC } from "cac" ;
34
45import { tryRunCommandCliRoute } from "../../utils/command-router.js" ;
@@ -11,10 +12,11 @@ import {
1112 parseNumberOption ,
1213} from "../../utils/options.js" ;
1314import { printJson } from "../../utils/output.js" ;
14- import { RuntimeContext } from "../../utils/runtime.js" ;
15+ import { type HaloClients , RuntimeContext } from "../../utils/runtime.js" ;
1516import { printMoment , printMomentList } from "./format.js" ;
1617import type { ListedMomentList , Moment , MomentVisible } from "./types.js" ;
1718
19+ const MOMENTS_PLUGIN_NAME = "PluginMoments" ;
1820const MOMENT_API_VERSION = "moment.halo.run/v1alpha1" ;
1921const MOMENT_KIND = "Moment" ;
2022const MOMENT_API_BASE = "/apis/uc.api.moment.halo.run/v1alpha1/moments" ;
@@ -46,6 +48,27 @@ interface MomentDeleteOptions extends MomentCommandOptions {
4648 force ?: boolean ;
4749}
4850
51+ async function ensureMomentsPluginInstalled ( clients : HaloClients ) : Promise < void > {
52+ try {
53+ const response = await clients . core . plugin . plugin . getPlugin ( { name : MOMENTS_PLUGIN_NAME } ) ;
54+ if ( ! response . data . spec . enabled ) {
55+ throw new CliError (
56+ `The ${ MOMENTS_PLUGIN_NAME } plugin is installed but not enabled. Enable it with: halo plugin enable ${ MOMENTS_PLUGIN_NAME } ` ,
57+ ) ;
58+ }
59+ } catch ( error ) {
60+ if ( error instanceof CliError ) {
61+ throw error ;
62+ }
63+ if ( axios . isAxiosError ( error ) && error . response ?. status === 404 ) {
64+ throw new CliError (
65+ `The ${ MOMENTS_PLUGIN_NAME } plugin is not installed. Install it from the App Store or via: halo plugin install` ,
66+ ) ;
67+ }
68+ throw error ;
69+ }
70+ }
71+
4972async function resolveMomentContent ( content ?: string ) : Promise < string | undefined > {
5073 return content ;
5174}
@@ -142,6 +165,12 @@ export function buildMomentPayload(
142165async function buildMomentCli ( runtime : RuntimeContext ) : Promise < CAC > {
143166 const momentCli = cac ( "halo moment" ) ;
144167
168+ async function getCheckedClients ( options : MomentCommandOptions ) {
169+ const result = await runtime . getClientsForOptions ( options ) ;
170+ await ensureMomentsPluginInstalled ( result . clients ) ;
171+ return result ;
172+ }
173+
145174 momentCli
146175 . command ( "list" , "List moments" )
147176 . option ( "--profile <name>" , "Halo profile name" )
@@ -153,7 +182,7 @@ async function buildMomentCli(runtime: RuntimeContext): Promise<CAC> {
153182 . option ( "--visible <state>" , "Filter by visibility: PUBLIC or PRIVATE" )
154183 . option ( "--approved <boolean>" , "Filter by approval state" )
155184 . action ( async ( options : MomentListOptions ) => {
156- const { clients } = await runtime . getClientsForOptions ( options ) ;
185+ const { clients } = await getCheckedClients ( options ) ;
157186 const response = await clients . axios . get < ListedMomentList > ( MOMENT_API_BASE , {
158187 params : {
159188 page : parseNumberOption ( options . page ) ,
@@ -173,7 +202,7 @@ async function buildMomentCli(runtime: RuntimeContext): Promise<CAC> {
173202 . option ( "--profile <name>" , "Halo profile name" )
174203 . option ( "--json" , "Output JSON" )
175204 . action ( async ( name : string , options : MomentCommandOptions ) => {
176- const { clients } = await runtime . getClientsForOptions ( options ) ;
205+ const { clients } = await getCheckedClients ( options ) ;
177206 const response = await clients . axios . get < Moment > (
178207 `${ MOMENT_API_BASE } /${ encodeURIComponent ( name ) } ` ,
179208 ) ;
@@ -191,7 +220,7 @@ async function buildMomentCli(runtime: RuntimeContext): Promise<CAC> {
191220 . option ( "--release-time <datetime>" , "Release time in ISO-8601 format" )
192221 . option ( "--approved <boolean>" , "Initial approval state" )
193222 . action ( async ( options : MomentMutationOptions ) => {
194- const { clients } = await runtime . getClientsForOptions ( options ) ;
223+ const { clients } = await getCheckedClients ( options ) ;
195224 const resolvedContent = await resolveMomentContent ( options . content ) ;
196225 const content = ( await promptForMomentContent ( resolvedContent ?. trim ( ) , "create" ) ) ?. trim ( ) ;
197226
@@ -216,7 +245,7 @@ async function buildMomentCli(runtime: RuntimeContext): Promise<CAC> {
216245 . option ( "--release-time <datetime>" , "Release time in ISO-8601 format" )
217246 . option ( "--approved <boolean>" , "Approval state" )
218247 . action ( async ( name : string , options : MomentMutationOptions ) => {
219- const { clients } = await runtime . getClientsForOptions ( options ) ;
248+ const { clients } = await getCheckedClients ( options ) ;
220249 const existingResponse = await clients . axios . get < Moment > (
221250 `${ MOMENT_API_BASE } /${ encodeURIComponent ( name ) } ` ,
222251 ) ;
@@ -260,7 +289,7 @@ async function buildMomentCli(runtime: RuntimeContext): Promise<CAC> {
260289 . option ( "--json" , "Output JSON" )
261290 . option ( "--force" , "Delete without confirmation" )
262291 . action ( async ( name : string , options : MomentDeleteOptions ) => {
263- const { clients } = await runtime . getClientsForOptions ( options ) ;
292+ const { clients } = await getCheckedClients ( options ) ;
264293
265294 if (
266295 ! ( await confirmDangerousAction (
0 commit comments